在ASP.NET Core应用程序中,我想创建某些角色作为管理不同用户权限的基础。遗憾的是,文档告知详细说明如何使用自定义角色,例如在控制器/操作中,但不是如何创建它们。我发现我可以使用RoleManager<IdentityRole>
来实现这一点,当实例在应用程序中注册其定义的ASP.NET核心标识时,会自动注入到控制器构造函数中。
这让我添加一个这样的自定义角色:
var testRole = new IdentityRole("TestRole");
if(!roleManager.RoleExistsAsync(testRole.Name).Result) {
roleManager.CreateAsync(testRole);
}
它可以在数据库中创建角色。但是这个检查总是会在数据库上产生开销,调用特定的控制器/动作。所以我想在我的应用程序启动后检查一次,如果自定义角色存在并添加它们。 Startup.cs中的ConfigureServices
方法似乎对此有用。
但是:如何创建RoleManager<IdentityRole>
类的实例来执行此操作?我想在这里使用最佳实践方法,而不是通过自己创建依赖实例来解决这个问题,这似乎会导致很多工作,因为它没有很好的文档化,并且肯定不会遵循最佳实践,因为ASP.NET Core正在使用依赖注入这样的事情(这在我的意见中也是合理的)。
换句话说:我需要在控制器的外部使用依赖注入。
答案 0 :(得分:25)
以下是您在启动时迁移和播种数据库的需求示例:
创建一个静态类:
public static class RolesData
{
private static readonly string[] Roles = new string[] {"Administrator", "Editor", "Subscriber"};
public static async Task SeedRoles(IServiceProvider serviceProvider)
{
using (var serviceScope = serviceProvider.GetRequiredService<IServiceScopeFactory>().CreateScope())
{
var dbContext = serviceScope.ServiceProvider.GetService<ApplicationDbContext>();
if (dbContext.Database.GetPendingMigrations().Any())
{
await dbContext.Database.MigrateAsync();
var roleManager = serviceScope.ServiceProvider.GetRequiredService<RoleManager<IdentityRole>>();
foreach (var role in Roles)
{
if (!await roleManager.RoleExistsAsync(role))
{
await roleManager.CreateAsync(new IdentityRole(role));
}
}
}
}
}
}
在Startup.cs
:
public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory)
{
...
RolesData.SeedRoles(app.ApplicationServices).Wait();
}
答案 1 :(得分:6)
我希望仅在数据库中没有插入角色时才播种数据。换句话说,仅在应用程序第一次运行时才存储角色:
public static class RolesData
{
private static readonly string[] Roles = new string[] { "Administrator", "Editor", "Subscriber" };
public static async Task SeedRoles(IServiceProvider serviceProvider)
{
using (var serviceScope = serviceProvider.GetRequiredService<IServiceScopeFactory>().CreateScope())
{
var dbContext = serviceScope.ServiceProvider.GetService<AppDbContext>();
if (!dbContext.UserRoles.Any())
{
var roleManager = serviceProvider.GetRequiredService<RoleManager<IdentityRole>>();
foreach (var role in Roles)
{
if (!await roleManager.RoleExistsAsync(role))
{
await roleManager.CreateAsync(new IdentityRole(role));
}
}
}
}
}
}
在Startup.cs上:
public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory)
{
...
RolesData.SeedRoles(app.ApplicationServices).Wait();
}
答案 2 :(得分:0)
以防万一有人来这里寻找 .NET 5 解决方案,这里是:
除了 Configure 方法中的一点之外,一切都与@Millan Sanchez 的回答几乎相同......
我得到了
One or more errors occurred. (Cannot resolve scoped service 'Microsoft.AspNetCore.Identity.RoleManager`1[Microsoft.AspNetCore.Identity.IdemtityRole]' from root provider.)'
又经过一番搜索,我发现了这个 StackOverflow answer
基本上,我需要做的就是将 IServiceProvider
添加到 Configure 方法的参数中,并将其传递给我对 SeedUsers 的调用,而不是 app.applicationServices
完整代码:
public static class RolesData
{
private static readonly string[] Roles = new string[] { "Administrator", "Editor", "Subscriber" };
public static async Task SeedRoles(IServiceProvider serviceProvider)
{
using (var serviceScope = serviceProvider.GetRequiredService<IServiceScopeFactory>().CreateScope())
{
var dbContext = serviceScope.ServiceProvider.GetService<AppDbContext>();
if (!dbContext.UserRoles.Any())
{
var roleManager = serviceProvider.GetRequiredService<RoleManager<IdentityRole>>();
foreach (var role in Roles)
{
if (!await roleManager.RoleExistsAsync(role))
{
await roleManager.CreateAsync(new IdentityRole(role));
}
}
}
}
}
}
在 Startup.cs 上:
public void Configure(IApplicationBuilder app, IWebHostEnvironment env,
IServiceProvider serviceProvider)
{
...
RolesData.SeedRoles(serviceProvider).Wait();
}