Идентификатор ядра ASP.NET Добавление пользовательских ролей при запуске приложений

В приложении ASP.NET Core я хочу создать определенные роли в качестве основы для управления различными правами пользователя. К сожалению, в документации сообщается о том, как использовать пользовательские роли, например. в контроллерах/действиях, но не в том, как их создавать. Я выяснил, что для этого могу использовать RoleManager<IdentityRole>, где экземпляр автоматически вводится в конструктор-контроллер, когда его идентификатор и идентификатор ядра ASP.NET регистрируются в приложении.

Это позволит мне добавить пользовательскую роль, подобную этой:

var testRole = new IdentityRole("TestRole");
if(!roleManager.RoleExistsAsync(testRole.Name).Result) {
    roleManager.CreateAsync(testRole);
}

Он работает и создает роль в базе данных. Но эта проверка всегда создает накладные расходы в базе данных, вызывая конкретный контроллер/действие. Поэтому я хочу проверить один раз после запуска моего приложения, если пользовательская роль существует и добавляет их. Метод ConfigureServices в Startup.cs кажется хорошим для этого.

Но: Как я могу создать экземпляр класса RoleManager<IdentityRole> для этого? Я хотел бы использовать подход с лучшей практикой здесь, а не вмешиваться, создавая отдельные экземпляры самостоятельно, что, кажется, вызывает много работы, поскольку оно не хорошо документировано и, несомненно, не будет следовать лучшим практикам, поскольку ASP.NET Core использует инъекции зависимостей для таких вещей (что также разумно в моем оппионе).

Другими словами: мне нужно использовать зависимую инъекцию вне контроллера.

Ответы

Ответ 1

Вот пример ваших потребностей, который переносит и заносит базу данных при запуске:

Создайте статический класс:

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();
}

Ответ 2

Я предпочел бы семенить данные только в том случае, если в базе данных уже нет ролей. В другом слове хранят роли только тогда, когда приложение запускается в первый раз:

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();
}