I am trying to create a class that seeds user and role data.
My class that seeds data takes a RoleManager
constructor parameter
public class IdentityDataSeeder
{
private readonly RoleManager<IdentityRole> roleManager;
public IdentityDataSeeder(RoleManager<IdentityRole> roleManager)
{
this.roleManager = roleManager;
}
public async Task SeedData()
{
// Do stuff with roleManager
}
}
I call it from Main
like this
public static async Task Main(string[] args)
{
var host = CreateHostBuilder(args).Build();
using (var scope = host.Services.CreateScope())
{
var dataSeeder = scope.ServiceProvider.GetService<IdentityDataSeeder>();
await dataSeeder.SeedData();
}
host.Run();
}
I configure my dependenies like this (note that I have two DbContexts
in my application; one context has my Identity tables, and the other context has my application tables).
public void ConfigureServices(IServiceCollection services)
{
services.AddDbContext<MyIdentityDbContext>(options =>
options.UseSqlServer(
Configuration.GetConnectionString("DefaultAdminConnection")));
services.AddDbContext<MyApplicationDbContext>(options =>
options.UseSqlServer(
Configuration.GetConnectionString("DefaultConnection")));
services.AddScoped<IdentityDataSeeder, IdentityDataSeeder>();
services.AddScoped<IRoleStore<IdentityRole>, RoleStore<IdentityRole>>();
services.AddScoped<RoleManager<IdentityRole>, RoleManager<IdentityRole>>();
}
My two context classes look like this
public class MyIdentityDbContext : IdentityDbContext
{
// ...
}
public class MyApplicationDbContext : DbContext
{
// ...
}
When I run the program, I get the error
InvalidOperationException: Unable to resolve service for type 'Microsoft.EntityFrameworkCore.DbContext' while attempting to activate 'Microsoft.AspNetCore.Identity.EntityFrameworkCore.RoleStore1[Microsoft.AspNetCore.Identity.IdentityRole]'.
I assume the problem is that since I have two DbContext
s registered in my dependencies, the service provider can't figure out which one to use when it tries to resolve RoleStore
(correct me if I'm wrong).
How do I tell the service provider to inject the MyIdentityDbContext
dependency into RoleStore
?
You will need to use the factory delegate with the ActivatorUtilities Class that uses the specific DbContext
resolved via the provider.
//...
services.AddScoped<IRoleStore<IdentityRole>>( sp => {
DbContext context = sp.GetService<MyIdentityDbContext>();
return ActivatorUtilities.CreateInstance<RoleStore<IdentityRole>>(sp, context);
});
//...
When resolving the role store, the service provider will use the provided DbContext
and resolve the remaining dependencies to be injected into the instance.