asp.net-mvcasp.net-coreasp.net-identityuser-rolesasp.net-roles

UserRoles seeding failed


I am developing an ASP.NET Core MVC web application. I employ the Identity UI framework for user authorization and authentication.

I have changed the primary key of all the Identity table to 'int' values (They are string type by default)

In the following code, I was trying to seed the predefined user roles as 'SuperAdmin', 'Admin', 'Businessman', and 'WaterEnthusiast' as follows:

using Microsoft.AspNetCore.Identity;
using System.Linq;
using System.Threading.Tasks;
using WATERrhythmWeb.Models;

namespace WATERrhythmWeb.Data
{
    public class ContextSeed
    {
        public static async Task SeedRolesAsync(UserManager<WaterrhythmUser> userManager, RoleManager<IdentityRole> roleManager)
        {
            //Seed Roles
            await roleManager.CreateAsync(new IdentityRole(Enums.Roles.SuperAdmin.ToString()));
            await roleManager.CreateAsync(new IdentityRole(Enums.Roles.Admin.ToString()));
            await roleManager.CreateAsync(new IdentityRole(Enums.Roles.Businessman.ToString()));
            await roleManager.CreateAsync(new IdentityRole(Enums.Roles.WaterEnthusiast.ToString()));
        }
    }
}

Following is the enum:

public enum Roles
{
    SuperAdmin,
    Admin,
    Businessman,
    WaterEnthusiast
}

And following is my DBContext class:

public partial class ApplicationDbContext : IdentityDbContext<WaterrhythmUser, IdentityRole<int>, int, IdentityUserClaim<int>, IdentityUserRole<int>, IdentityUserLogin<int>, IdentityRoleClaim<int>, IdentityUserToken<int>>
{
    public ApplicationDbContext(DbContextOptions<ApplicationDbContext> options)
        : base(options)
    {
    }
    protected override void OnModelCreating(ModelBuilder builder)
    {
        base.OnModelCreating(builder);
        builder.HasDefaultSchema("Identity");
        modelBuilder.Entity<WaterrhythmUser>(entity =>
        {
            entity.ToTable(name: "User");
        });
        modelBuilder.Entity<IdentityRole>(entity =>
        {
            entity.ToTable(name: "WATERrhythmRole");
        });
        modelBuilder.Entity<IdentityUserRole<int>>(entity =>
        {
            entity.ToTable("WATERrhythmUserRoles");
        });

        modelBuilder.Entity<IdentityUserClaim<int>>(entity =>
        {
            entity.ToTable("WATERrhythmUserClaims");
        });

        modelBuilder.Entity<IdentityUserLogin<int>>(entity =>
        {
            entity.ToTable("WATERrhythmUserLogins");
        });

        modelBuilder.Entity<IdentityRoleClaim<int>>(entity =>
        {
            entity.ToTable("WATERrhythmRoleClaims");

        });

        modelBuilder.Entity<IdentityUserToken<int>>(entity =>
        {
            entity.ToTable("WATERrhythmUserTokens");
        });
    }
}

According to the tutorial, after the above modifications, when I run the application the user roles defined above should be seeded in the database table: 'IdentityRole'.

But when I run the application (having created the migrations and update the new database), it does not create any user roles.

Can someone please tell me how to rectify this issue, please?

Thank you.

(As you can see I have changed the primary key of those tables to 'int'. I am curious whether it causes this issue.)


Solution

  • But when I run the application (having created the migrations and update the new database), it does not create any user roles.

    It sounds like you may have forgotten to invoke SeedRolesAsync anywhere.

    If it's not the case, I see something that may cause some troubles. In your configuration, you're doing config for IdentityRole, but in the DbContext, you have IdentityRole<int>. Even in your seeding method, there's no <int> but default IdentityRole. You should change each IdentityRole into IdentityRole<int>.

    However, I think that a cleaner solution for seeding such dictionary tables would be using HasData of EF Core's fluent API. It could look like this in your case:

    modelBuilder.Entity<IdentityRole<int>>(entity =>
    {
        entity.ToTable(name: "WATERrhythmRole");
        entity.HasData(
            new IdentityRole<int>
            {
                Id = 1,
                Name = Roles.SuperAdmin.ToString(),
                NormalizedName = Roles.SuperAdmin.ToString().ToUpper()
            },
            new IdentityRole<int>
            {
                Id = 2,
                Name = Roles.Admin.ToString(),
                NormalizedName = Roles.Admin.ToString().ToUpper()
            }
        );
    });
    

    This way there would be no reason to create an additional method and run it from somewhere in order to seed the database.