I am working on an AspNetCore 2.1 WebApi. I am using Microsoft.Extensions.DependencyInjection
, AspNetCore.Identity
, and EntityFrameworkCore
.
In my DI registrations, I am calling:
services.AddDbContext<IMyDbContext, MyDbContext>();
Good, right? Pass around the contract. But then I hit an exception that the Identity Manager classes (UserManager
, RoleManager
, etc.) cannot be respolved in the Dependency Injection container because the Identity Stores they use (UserStore
, RoleStore
, etc.) cannot resolve their DI parameter (MyDbContext
).
It all points to this line when setting up Identity:
builder.AddEntityFrameworkStores<MyDbContext>();
... which is puking since the Identity Stores are looking for the concrete context and it is not registered with DI. The extension is expecting a class
that it can resolve down to DbContext
- and I cannot add an implicit operator to the interface IMyDbContext
to give it an implicit cast the DI extension method could use.
All this has me performing a rather ugly DI registration:
services
.AddDbContext<IMyDbContext, MyDbContext>()
.AddDbContext<MyDbContext>();
My guess is that I could clean up the DI registration by rolling my own IServiceCollection
extension and/or custom Identity Stores - which really seems like overkill here as I otherwise have no need to go beyond the default built-in Identity Stores.
I also don't really want to remove the <interface, concrete>
context registration as that will trickle down to all my constructor injections, and just seems wrong.
Has anybody tackled this already and found a work-around? Or can anybody at least confirm/deny that the double (interface && concrete) context registration in the DI will not cause other issues?
Thanks in advance!
By default, when you call AddDbContext
, you register a scoped DbContext
instance. This means that anywhere within the handling of a single request, requesting said DbContext
via DI will give you the same instance. With the double registration you have, the DI system will give you a different instance depending upon whether you ask for an IMyDbContext
or a MyDbContext
.
To instruct the DI system to give you the same instance for both types, use the following approach:
services.AddDbContext<MyDbContext>();
services.AddScoped<IMyDbContext>(sp => sp.GetRequiredService<MyDbContext>());
The first call registers MyDbContext
and the second simply forwards requests for IMyDbContext
to that same scoped MyDbContext
instance.