简体   繁体   中英

ASP.NET Core DI with Simple Injector sharing DbContext

I'm setting up an ASP.NET Core project and following a CQRS pattern basing my work on the Tripod project. I've followed the Simple Injector integration guide but a little puzzled on one point... I want to keep make use of the UseInMemoryDatabase option for testing and can only find examples of that using the Core DI AddDbContext method.

My DbContext implement several interfaces:

public class EntityDbContext : DbContext,
    IUnitOfWork,
    IReadEntities,
    IWriteEntities
{
    // code here
}

I'm doing this in the Startup.ConfigureServices method:

services.AddDbContext<EntityDbContext>(options => options.UseInMemoryDatabase("Snoogans"));

and following the SI integration guide this in the Startup.Configure method:

container.Register<IUnitOfWork, xxxx>();
container.Register<IReadEntities, xxxx>();
container.Register<IWriteEntities, xxxx>();

Am I able to get the Core registration over crosswire to plugin to the target for each of them or should I just be registering the context directly in SI?

== I'm playing around with the original concept from Tripod:

var contextRegistration =
    lifestyle.CreateRegistration<EntityDbContext, EntityDbContext>(container);
container.AddRegistration(typeof(EntityDbContext), contextRegistration);
container.AddRegistration(typeof(IUnitOfWork), contextRegistration);
container.AddRegistration(typeof(IWriteEntities), contextRegistration);
container.AddRegistration(typeof(IReadEntities), contextRegistration);

trying to do everything with SI, but not sure how I get at the Registration for the 3 interfaces:

container.Register<EntityDbContext>(() =>
{
    var optionsBuilder =
        new DbContextOptionsBuilder<EntityDbContext>().UseInMemoryDatabase("Snoogans");
    return new EntityDbContext(optionsBuilder.Options);
});
container.AddRegistration<IUnitOfWork>(xxxx);
container.AddRegistration<IReadEntities>(xxxx);
container.AddRegistration<IWriteEntities>(xxxx);

Am I able to get the Core registration over crosswire to plugin to the target for each of them or should I just be registering the context directly in SI?

Both options are feasible. You can chose to register the DbContext directly into Simple Injector. This would typically be the most obvious choice as your DbContext is an application component. Application components should typically be registered in your application container (ie Simple Injector) instead of in the framework's registration system (ie ServiceCollection ).

When it comes to registering DbContext , however, there is some tight integration with the ASP.NET Core configuration system. This can make it more straightforward to do the registration there and simply cross-wire from Simple Injector. That lets the configuration system stay in control over the creation and destruction of the DbContext. This becomes especially valuable when doing things like DbContext pooling, as this pooling functionality is tightly coupled with this configuration and registration API.

Typically, both options are pretty straightforward, but because your DbContext implements multiple interfaces that you want to register seperately, this causes your registrations to become more complicated. This would have been the case as well in case you're using the built-in DI Container as well, so this is not specific to Simple Injector.

In your case, doing the registrations purely in Simple Injector would look like this:

var reg = Lifestyle.Scoped.CreateRegistration(() =>
    {
        var optionsBuilder =
            new DbContextOptionsBuilder<EntityDbContext>().UseInMemoryDatabase("Snoogans");
        return new EntityDbContext(optionsBuilder.Options);
    },
    container);

container.AddRegistration<IUnitOfWork>(reg);
container.AddRegistration<IReadEntities>(reg);
container.AddRegistration<IWriteEntities>(reg);

In case you chose to cross-wire your DbContext from the .NET Core configuration system, your configuration would look as follows:

// Add to the built-in ServiceCollection
services.AddDbContext<EntityDbContext>(options => options.UseInMemoryDatabase("Snoogans"));

// Cross-wire in Simple Injector
container.CrossWire<EntityDbContext>(app);

// Pull that registration out of Simple Injector and use it for the interface registrations
var reg = container.GetRegistration(typeof(EntityDbContext)).Registration;

// Same as before
container.AddRegistration<IUnitOfWork>(reg);
container.AddRegistration<IReadEntities>(reg);
container.AddRegistration<IWriteEntities>(reg);

If you wouldn't be using Simple Injector, but purely .NET Core's built-in DI Container, the registration would look as follows:

services.AddDbContext<EntityDbContext>(options => options.UseInMemoryDatabase("Snoogans"));

services.AddScoped<IUnitOfWork>(c => c.GetRequiredService<EntityDbContext>());
services.AddScoped<IReadEntities>(c => c.GetRequiredService<EntityDbContext>());
services.AddScoped<IWriteEntities>(c => c.GetRequiredService<EntityDbContext>());

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM