Skip to content

Installing GenericServices

Jon P Smith edited this page Jul 14, 2018 · 7 revisions

This page tells you how to set up GenericServices in your application. The steps are:

  • Install the NuGet library EfCore.GenericServices in the main application so that
    • You can register it with .NET Core dependency injection (DI) service, and...
    • ... you can use ICrudServices in your front-end code.
  • Install the same EfCore.GenericServices library in the project/assembly where your DTOs are, so that you can apply the ILinkToEntity<TEntity> interface to mark the DTOs.

Registering GenericServices with DI in ASP.NET Core

Once you have installed the EfCore.GenericServices NuGet in your ASP.NET Core application you need to register it in the ConfigureService method in the Startup.cs class.

The simplest approach, which assumes you have one application's DbContext, can be done with one extension method called GenericServicesSimpleSetup<TContext>. You can see how I did this my the RazorPageApp here, but I have repeated the code below.

services.GenericServicesSimpleSetup<EfCoreContext>(
   Assembly.GetAssembly(typeof(BookListDto)));

or, if you want to provide some configration then it looks like this

services.GenericServicesSimpleSetup<DevDbContext>(new GenericServicesConfig
    {
        DtoAccessValidateOnSave = true,     //we use  Dto access for Create/Update
        DirectAccessValidateOnSave = true,  //And direct access for Delete
        SaveChangesExceptionHandler = GenericServiceErrorHandler.SaveChangesExceptionHandler
}, Assembly.GetAssembly(typeof(BookListDto)));

The key parts are:

  1. You must provide the type of your application's DbContext, and that context must have already been registered with DI. GenericServices will register all the entity classes and also register your application's DbContext against the DbContext class.
  2. You need to provide the assemblies that your DTOs are in. I do this by using GetAssembly of one of my DTOs.

Advanced notes:

  • GenericServices can handle multiple DbContexts (known in DDD as bounded contexts). To configure these you need to use a more complex registration arrangement, as shown below
services.ConfigureGenericServicesEntities(typeof(BookDbContext), typeof(OrderDbContext))
    .ScanAssemblesForDtos(Assembly.GetAssembly(typeof(BookListDto)))
    .RegisterGenericServices();

Setting up your DTOs

I describe this in great detail the GenericServices and DTOs page, but basically the DTO needs the empty interface ILinkToEntity<TEntity> added it so that GenericServices can find it, and work out what entity class it is linked to.

The other thing I recommend you do is add a [ReadOnly(true)] attribute to all the properties in the DTO that you DON'T want copied back into the entity class - that is a security feature to stop the wrong properties being updated (DDD-styled entity classes are safe without these, but it helps GenerricServices in finding the right method to call).

Optional CopyErrorsToModelState extension method

There is a NuGet library called EfCore.GenericServices.AspNetCore which contains an extension method called CopyErrorsToModelState, which converts the GenericServices' IStatusGeneric into errors in the ASP.NET Core's ModelState. All the example razor pages uses this - here is an example

public void OnGet(int id)
{
    Data = _service.ReadSingle<AddReviewDto>(id);
    //The service will have an error (i.e. _service.IsValid is false) 
    //if there is no entity with that id
    if (!_service.IsValid)
    {
       //This will copy any errors to the ModelState
       //if any of the errors have a property name that matches a Data class's 
       //property name then the method marks the error with that name so that 
       //the error message will appear next to the input field.
       //NOTE: For razor pages you need to prefix the property name with the name 
       //of the PageModel property, which you can do via the optional third param
        _service.CopyErrorsToModelState(ModelState, Data, nameof(Data));
    }
}
You can’t perform that action at this time.