Dans une application ASP.NET Core, je souhaite créer certains rôles comme base pour gérer différentes autorisations utilisateur. Malheureusement, la documentation indique comment utiliser des rôles personnalisés, par exemple dans les contrôleurs/actions, mais pas comment les créer. J'ai découvert que je peux utiliser RoleManager<IdentityRole>
pour cela, où l'instance est automatiquement injectée dans un constructeur de contrôleur, lorsque son identité définie et ASP.NET Core est enregistrée dans l'application.
Cela me permet d'ajouter un rôle personnalisé comme celui-ci:
var testRole = new IdentityRole("TestRole");
if(!roleManager.RoleExistsAsync(testRole.Name).Result) {
roleManager.CreateAsync(testRole);
}
Cela fonctionne et crée le rôle dans la base de données. Mais cette vérification créera toujours une surcharge sur la base de données, appelant le contrôleur/l'action spécifique. Je veux donc vérifier ne fois après le démarrage de mon application, si le rôle personnalisé existe et les ajouter. La méthode ConfigureServices
dans Startup.cs semble bonne pour cela.
Mais: comment puis-je créer une instance de RoleManager<IdentityRole>
classe pour faire ça? Je voudrais utiliser une approche des meilleures pratiques ici et ne pas déconner en créant moi-même des instances dépendantes, ce qui semble causer beaucoup de travail car ce n'est pas bien documenté et ne suivra certainement pas les meilleures pratiques, car ASP.NET Core utilise injection de dépendance pour des choses comme celle-ci (ce qui est également raisonnable à mon avis).
En d'autres termes: j'ai besoin d'utiliser l'injection de dépendance extérieur d'un contrôleur.
Voici un exemple pour vos besoins qui migre et amorce la base de données au démarrage:
Créez une classe statique:
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));
}
}
}
}
}
}
Et en Startup.cs
:
public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory)
{
...
RolesData.SeedRoles(app.ApplicationServices).Wait();
}
Je préférerais semer les données uniquement s'il n'y a pas de rôles déjà insérés dans la base de données. Dans d'autres magasins Word, les rôles ne sont disponibles que lorsque l'application est exécutée pour la première fois:
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));
}
}
}
}
}
}
Et sur Startup.cs:
public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory)
{
...
RolesData.SeedRoles(app.ApplicationServices).Wait();
}