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.
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();
}
I would prefer to seed the data only if there are no roles already inserted in the database. In other word store the roles only when the application is running for the first time:
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));
}
}
}
}
}
}
And on Startup.cs:
public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory)
{
...
RolesData.SeedRoles(app.ApplicationServices).Wait();
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With