-
Notifications
You must be signed in to change notification settings - Fork 95
Installing GenericServices
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. - If you are using DDD-styled classes with EF Core, then you need to add the NuGet library GenericServices.StatusGeneric if you want to return
IStatusGeneric
from your DDD methods - see What does GenericServices expect in a DDD-styled entity?.
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)));
The key parts are:
- 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. - You need to provide the assemblies that your DTOs are in. I do this by using
GetAssembly
of one of my DTOs.
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();
If you want to provide some configuration 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)));
See Configuration Options for what all the settings are.
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).
There is a NuGet library called EfCore.GenericServices.AspNetCore which contains an extension method called CopyErrorsToModelState
, which converts the IStatusGeneric
into errors in the ASP.NET Core's ModelState
, or for Web APIs.
Please look at the README file for this project for more information.
All the example razor pages on the EfCore.GenericServices repo 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));
}
}