Skip to content

Configuration options

Jon P Smith edited this page Nov 23, 2019 · 8 revisions

Configuration options

There are four main parts of the GenericServicesConfig class.

1. Validation

NOTE: By validation I mean using the Validator.TryValidateObject method on every entity being written to the database.

By default GenericServices does NOT validate data written to the database - it assumes that the front-end has validated the data. But it can be useful to turn on validation, especially if you are using the SaveChangesExceptionHandler fuction - (see below).

You have two ways to turn on validation when GenericServices calls SaveChanges - globally via the GenericServicesConfig class at startup (see below), or individually using the PerDtoConfig<TDto, TEntity.

GenericServicesConfig.DirectAccessValidateOnSave

If set to true then any Create/Update/Delete that is given an entity classes will validate that entity class on save. It will also call the SaveChangesExceptionHandler (see below) if an exception occurs. This is the ONLY way to turn on validation for direct-access writes

GenericServicesConfig.DtoAccessValidateOnSave

If set to true then any Create/Update/Delete calls with DTOs will include a validation of the data on save. It will also call the SaveChangesExceptionHandler (see below) if an exception occurs. You can use PerDtoConfig<TDto, TEntity to only set validation for a single DTO/entity. The PerDtoConfig setting takes precedence, and can force validation on or off.

2. Injecting before SaveChanges

GenericServicesConfig.BeforeSaveChanges

If you assign a method to the BeforeSaveChanges property in GenericServicesConfig, then it will be called just before SaveChanges/Async is called. The method takes in the current DbContext, which allows you access to the ChangeTracker method to find out the state of all the tracked entities. The method returns an IStatusGeneric result and if that status result has errors, i.e. status.IsValid == false, then it will not call SaveChanges/Async.
How you use this is up to you, but here are some suggestions:

  1. Add your own validation approach - someone wanted this to apply fluentvalidation.
  2. Maybe add some code to update certain entities.
  3. Logging. etc.

3. SQL Error handling

GenericServicesConfig.SaveChangesExceptionHandler

If you set this property to a method it will be called if there is an exception when SaveChanges/Async is called. You method should either:

  1. Return a IStatusGeneric if it handled the exception (either by returning a error message or a status message) if it successfully converted the exception into a user-friendly error that you can show to user.
  2. Returns null if it didn't recognise the exception/error and couldn't handle it. In that case the code will rethrow the exception and it will bubble up to the top.

See the article Entity Framework Core – validating data and catching SQL errors for an example of how to do this.

4. ReadSingle and nulls

Whether returning a null from a ReadSingle/ReadSingleAsync is an error or not depends on what you are doing. For instance, when working with html/razor you most likely want to tell the user that was an error. But with Web API it's not an error - you just return NotFound (HTTP 404).

GenericServicesConfig.NoErrorOnReadSingleNull

You can control whether the read of null is an error via the NoErrorOnReadSingleNull property in the config. By default it adds an error, but if set to true it will not add an error, but it will set the Message to "The <Class Name> was not found."

5. Name matching

The name matcher is used to match the properties in a DTO with the property names in your DDD-styled entity access methods. The default name matcher matches camel and Pascal-case words by simple string matching. If you want a different matching scheme you can write your own, using the DefaultNameMatcher as a template.

Clone this wiki locally