Reputation: 585
In my Blazor, .Net Core 3.1 server side app, I recently changed the EF contect scoping from transient to using a factory extension and it works well. However, I added the same dbcontext factory code to a second project that uses Identity & I get Exceptions on startup.
InvalidOperationException: Unable to resolve service for type 'OMS.DALInterfaces.Models.OmsDbContext' while attempting to activate 'Microsoft.AspNetCore.Identity.EntityFrameworkCore.UserStore`9
This worked fine when no factory class was in use (ie let DI handle the OMSDbContext)
services.AddDbContext<OmsDbContext>(options =>
options.UseSqlServer(Configuration.GetConnectionString("DefaultConnection")),
ServiceLifetime.Transient
);
services.AddDefaultIdentity<IdentityUser>(options => options.SignIn.RequireConfirmedAccount = true)
.AddRoles<IdentityRole>()
.AddEntityFrameworkStores<OmsDbContext>();
Now in the project using Identity I tried:
services.AddDbContextFactory<OmsDbContext>(opt =>
opt.UseSqlServer(Configuration.GetConnectionString("DefaultConnection"))
.EnableSensitiveDataLogging());
services.AddDefaultIdentity<IdentityUser>(options => options.SignIn.RequireConfirmedAccount = true)
.AddRoles<IdentityRole>()
.AddEntityFrameworkStores<OmsDbContext>();
So how do you define Identity in startup when using the Factory extension?
Upvotes: 12
Views: 4986
Reputation: 33
Another option that works for me is to use ServiceLifetime.Transient
when adding DbContext
public void ConfigureServices(IServiceCollection services){
services
.AddDbContextFactory<ApplicationDbContext>(options =>
options.UseSqlServer(connectionString));
services
.AddDbContext<ApplicationDbContext>(options =>
options.UseSqlServer(connectionString),ServiceLifetime.Transient);
services
.AddDefaultIdentity<IdentityUser>(options =>
options.SignIn.RequireConfirmedAccount = true)
.AddEntityFrameworkStores<ApplicationDbContext>();
}
Upvotes: 0
Reputation: 99
It's because the Identity EntityFrameworkStores assume your DbContext
is also available via dependency injection.
What you're doing is adding the factory but not adding your DbContext
itself.
You need to add both.
void BuildOptions(DbContextOptionsBuilder options) => options
.UseSqlServer(Configuration.GetConnectionString("DefaultConnection"))
.EnableSensitiveDataLogging();
services.AddDbContext<OmsDbContext>(BuildOptions);
services.AddDbContextFactory<OmsDbContext>(BuildOptions);
services.AddDefaultIdentity<IdentityUser>(options =>
options.SignIn.RequireConfirmedAccount = true)
.AddRoles<IdentityRole>()
.AddEntityFrameworkStores<OmsDbContext>();
Upvotes: 0
Reputation: 327
Craig, got it figured out for us.
In ConfigureServices, AddScoped of the DbContext and use the provider to get the factory from the services. Then, return the instance to the provider, as follows. The specs for Identity use scoped so I use scoped here.
services.AddDbContextFactory<ApplicationDbContext>(options =>
{
options.UseSqlServer(Configuration.GetConnectionString("DefaultConnection"));
options.EnableSensitiveDataLogging();
});
services.AddScoped<ApplicationDbContext>(p => p.GetRequiredService<IDbContextFactory<ApplicationDbContext>>().CreateDbContext());
Upvotes: 24