Reputation: 1429
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);
Upvotes: 2
Views: 1444
Reputation: 172646
If you weren't implementing multiple interfaces on your DbContext
, this would be the only line of code needed to gets things up and running in Simple Injector:
// Add to the built-in ServiceCollection
services.AddDbContext<EntityDbContext>(o => o
.UseInMemoryDatabase("Snoogans"));
Using the Simple Injector integration packages, that framework dependency is automatically pulled in into Simple Injector. So any class that is resolved from Simple Injector can be injected with your EntityDbContext
, even though it is only registered in the IServiceCollection
.
Your case, however, is more complex as you're implementing multiple interfaces on your DbContext
, while the DbContext
registration is tightly coupled to the built-in DI infrastructure.
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 choose 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 (i.e. Simple Injector) instead of in the framework's registration system (i.e. ServiceCollection
).
When it comes to registering DbContext
, however, there is some unfortunate coupling with the ASP.NET Core configuration system. This can make it more straightforward to do the registration there instead. 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, i.e. you can't use DbContext
pooling without calling services.AddDbContextPool<T>
.
Typically, both options are pretty straightforward, but because your DbContext
implements multiple interfaces that you want to register separately, 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 choose 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>(o => o
.UseInMemoryDatabase("Snoogans"));
// These registrations request EntityDbContext from Simple Injector.
// While it is not registered directly, Simple Injector will pull it
// in automatically from .NET core. This is auto cross-wiring.
container.Register<IUnitOfWork>(() => container.GetInstance<EntityDbContext>());
container.Register<IReadEntities>(() => container.GetInstance<EntityDbContext>());
container.Register<IWriteEntities>(() => container.GetInstance<EntityDbContext>());
If you wouldn't be using Simple Injector, but purely .NET Core's built-in DI Container, the registration would look very similar:
services.AddDbContext<EntityDbContext>(o => o
.UseInMemoryDatabase("Snoogans"));
services.AddScoped<IUnitOfWork>(c => c.GetRequiredService<EntityDbContext>());
services.AddScoped<IReadEntities>(c => c.GetRequiredService<EntityDbContext>());
services.AddScoped<IWriteEntities>(c => c.GetRequiredService<EntityDbContext>());
Upvotes: 4