ASP.NET Core Identity Add custom user roles on application startup

Lion picture Lion · Oct 8, 2016 · Viewed 12.5k times · Source

In an ASP.NET Core application, I want to create certain roles as a basis to manage different user-permissions. Sadly, the documentation inform detailled how to use custom roles e.g. in controllers/actions, but not how to create them. I found out that I can use RoleManager<IdentityRole> for this, where the instance gets automatically injected in a controller-constructor, when its defined and ASP.NET Core identity is registered in the application.

This let me add a custom role like this:

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

It works and create the role in the database. But this check will always create overhead on the database, calling the specific controller/action. So I want to check once after my application has started, if the custom role exists and add them. The ConfigureServices method in Startup.cs seems good for this.

But: How can I create a instance of the RoleManager<IdentityRole> class for doing this? I would like to use a best practice approach here and not messing around by creating depending instances on my own, which seems to cause a lot of work since its not good documentated and will surely not follow best practices, since ASP.NET Core is using dependency injection for things like this (which is also reasonable in my oppinion).

In other words: I need to use dependeny injection outside of a controller.

Answer

tmg picture tmg · Oct 8, 2016

Here is an example for your needs that migrates and seeds the database on startup:

Create a static class:

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

And in Startup.cs:

public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory)
{
    ...

    RolesData.SeedRoles(app.ApplicationServices).Wait();
}