I am trying to check if AppRoles exit in the database and if not create AppRoles as show below. However, I got System.InvalidOperationException: 'Cannot resolve scoped service 'Microsoft.AspNetCore.Identity.RoleManager`1[Microsoft.AspNetCore.Identity.IdentityRole]' from root provider.' exception when i built the app
using (var serviceScope = app.Services.CreateScope()) {
var services = serviceScope.ServiceProvider;
var dbContext = services.GetRequiredService<AppDbContext>();
dbContext.Database.EnsureCreated();
var roleManager = app.Services.GetRequiredService<RoleManager<IdentityRole>>();
if (! await roleManager.RoleExistsAsync(AppRoles.User))
{
await roleManager.CreateAsync(new IdentityRole(AppRoles.User));
}
if (! await roleManager.RoleExistsAsync(AppRoles.Editor))
{
await roleManager.CreateAsync(new IdentityRole(AppRoles.Editor));
}
if (!await roleManager.RoleExistsAsync(AppRoles.Administrator))
{
await roleManager.CreateAsync(new IdentityRole(AppRoles.Administrator));
}
}
I expect the roles to created if the roles does not exit in the DB already
The RoleManager service is resolved from the scope service provider, not from the root service provider. Therefore, you need to obtain the RoleManager service when creating the scope.In addition, you need to configure the corresponding rolemanager service:
builder.Services.AddIdentity<IdentityUser, IdentityRole>(options => options.SignIn.RequireConfirmedAccount = true) .AddEntityFrameworkStores<AppDbContext>();
In this way, the RoleManager service can be correctly registered and used in the application. The following is a complete example for reference:
var builder = WebApplication.CreateBuilder(args);
// Add services to the container.
var connectionString = builder.Configuration.GetConnectionString("DefaultConnection") ?? throw new InvalidOperationException("Connection string 'DefaultConnection' not found.");
builder.Services.AddDbContext<AppDbContext>(options =>
options.UseSqlServer(connectionString));
builder.Services.AddDatabaseDeveloperPageExceptionFilter();
builder.Services.AddIdentity<IdentityUser, IdentityRole>(options => options.SignIn.RequireConfirmedAccount = true)
.AddEntityFrameworkStores<AppDbContext>();
builder.Services.AddControllersWithViews();
builder.Services.AddRazorPages();
var app = builder.Build();
// Configure the HTTP request pipeline.
if (app.Environment.IsDevelopment())
{
app.UseMigrationsEndPoint();
}
else
{
app.UseExceptionHandler("/Home/Error");
// The default HSTS value is 30 days. You may want to change this for production scenarios, see https://aka.ms/aspnetcore-hsts.
app.UseHsts();
}
app.UseHttpsRedirection();
app.UseStaticFiles();
app.UseRouting();
app.UseAuthorization();
using (var serviceScope = app.Services.CreateScope())
{
var services = serviceScope.ServiceProvider;
var dbContext = services.GetRequiredService<AppDbContext>();
dbContext.Database.EnsureCreated();
var roleManager = services.GetRequiredService<RoleManager<IdentityRole>>();
if (!await roleManager.RoleExistsAsync(AppRoles.User))
{
await roleManager.CreateAsync(new IdentityRole(AppRoles.User));
}
if (!await roleManager.RoleExistsAsync(AppRoles.Editor))
{
await roleManager.CreateAsync(new IdentityRole(AppRoles.Editor));
}
if (!await roleManager.RoleExistsAsync(AppRoles.Administrator))
{
await roleManager.CreateAsync(new IdentityRole(AppRoles.Administrator));
}
}
app.MapControllerRoute(
name: "default",
pattern: "{controller=Home}/{action=Index}/{id?}");
app.MapRazorPages();
app.Run();