Search code examples
asp.net-mvcentity-frameworkasp.net-identityasp.net-identity-2user-roles

Can't extend IdentityUserRole.cs to add new composite key to dbo.AspNetUserRoles table ASP.NET Identity 2.1


I am trying to build Membership system using ASP.NET Identity 2.1, ASP.NET Web API 2.2 and i need to extend IdentityUserRole to add another PK to its table like that:

public class ApplicationUserRoles : IdentityUserRole
{
    public Guid ProjectId { get; set; }
    public Project Project { get; set; }
}

public class Project
{
    public Project()
    {
        ProjectId = new Guid();
    }

    public string ProjectName { get; set; }
    [Key]
    public Guid ProjectId { get; set; }
}

And in the DBcontext class I added :

protected override void OnModelCreating(System.Data.Entity.DbModelBuilder modelBuilder)
{
    base.OnModelCreating(modelBuilder); // This needs to go before the other rules!

    modelBuilder.Entity<ApplicationUserRoles>().HasKey(m => new {m.ProjectId, m.UserId, m.RoleId}).ToTable("ApplicationUserRoles");

}

public DbSet<ApplicationUserRoles> ApplicationUserRoles { get; set; }

and this did not work at all , i do not what i did wrong , add migration keep generate :

CreateTable(
        "dbo.ApplicationUserRoles",
        c => new
            {
                UserId = c.String(nullable: false, maxLength: 128),
                RoleId = c.String(nullable: false, maxLength: 128),
                ProjectId = c.Guid(nullable: false),
            })
        .PrimaryKey(t => new { t.UserId, t.RoleId })
        .ForeignKey("dbo.AspNetUserRoles", t => new { t.UserId, t.RoleId })
        .ForeignKey("dbo.Projects", t => t.ProjectId, cascadeDelete: true)
        .Index(t => new { t.UserId, t.RoleId })
        .Index(t => t.ProjectId);

}

As you can see PrimaryKey(t => new { t.UserId, t.RoleId }). I need it to be PrimaryKey(t => new { t.ProjectId,t.UserId, t.RoleId })


Solution

  • I got it work finally and here what i did :

    at the signature of IdentityUser myApplicationUser inherits from it

    public class IdentityUser<TKey, TLogin, TRole, TClaim> : IUser<TKey>
        where TLogin : Microsoft.AspNet.Identity.EntityFramework.IdentityUserLogin<TKey>
        where TRole : Microsoft.AspNet.Identity.EntityFramework.IdentityUserRole<TKey>
        where TClaim : Microsoft.AspNet.Identity.EntityFramework.IdentityUserClaim<TKey>
    {
    
    }
    

    it accepts my custom definition of IdentityUserRole.

    my class ApplicationUser i needed to implement the right type:

    public class ApplicationUser : IdentityUser<string, IdentityUserLogin, ApplicationUserSecurityProfile, IdentityUserClaim>
    {
    
    }
    

    and my role:

    public class ApplicationSecurityProfile : IdentityRole<string, ApplicationUserSecurityProfile>
    {
    }
    

    and my ApplicationDbContext:

    public class ApplicationDbContext : IdentityDbContext<ApplicationUser, ApplicationSecurityProfile, string, IdentityUserLogin, ApplicationUserSecurityProfile, IdentityUserClaim>, IContext
    {
    
    }
    

    and my UserStore:

    public class ApplicationUserStore : UserStore<ApplicationUser, ApplicationSecurityProfile, string, IdentityUserLogin, ApplicationUserSecurityProfile, IdentityUserClaim>, IUserStore<ApplicationUser>
    {
        public ApplicationUserStore ApplicationDbContext context)
            : base(context)
        {
        }
    }
    

    and myRoleStore :

     public class ApplicationSecurityProfileStore : RoleStore<ApplicationSecurityProfile, string, ApplicationUserSecurityProfile>
        {
            public ApplicationSecurityProfileStore(ApplicationDbContext context)
                : base(context)
            {
            }
    
    
        }
    

    then i used my custom classes in the my custom mangers :

    RoleManger :

    public class ApplicationSecurityProfileManager : RoleManager<ApplicationSecurityProfile>
    {
        private ApplicationDbContext db = new ApplicationDbContext();
    
        public ApplicationSecurityProfileManager(IRoleStore<ApplicationSecurityProfile, string> roleStore)
            : base(roleStore)
        {
        }
    
    
    
    public static ApplicationSecurityProfileManager Create(IdentityFactoryOptions<ApplicationSecurityProfileManager> options, IOwinContext context)
        {
    
            var appRoleManager = new ApplicationSecurityProfileManager(new ApplicationSecurityProfileStore(context.Get<ApplicationDbContext>()));
    
            return appRoleManager;
        }
    
    }
    

    my UserManager

    public class ApplicationUserManager : UserManager<ApplicationUser>
    {
        public ApplicationUserManager(ApplicationUserStore store)
            : base(store)
        {
        }
    
        public static ApplicationUserManager Create(IdentityFactoryOptions<ApplicationUserManager> options, IOwinContext context)
        {
            var appDbContext = context.Get<ApplicationDbContext>();
            var appUserManager = new ApplicationUserManager(new ApplicationUserStore(appDbContext));
    
            // Configure validation logic for usernames
            appUserManager.UserValidator = new UserValidator<ApplicationUser>(appUserManager)
            {
                AllowOnlyAlphanumericUserNames = true,
                RequireUniqueEmail = true
            };
    
            // Configure validation logic for passwords
            appUserManager.PasswordValidator = new PasswordValidator
            {
                RequiredLength = 6,
                RequireNonLetterOrDigit = true,
                RequireDigit = false,
                RequireLowercase = true,
                RequireUppercase = true,
            };
    
            appUserManager.EmailService = new AspNetIdentity.WebApi.Services.EmailService();
    
            var dataProtectionProvider = options.DataProtectionProvider;
            if (dataProtectionProvider != null)
            {
                appUserManager.UserTokenProvider = new DataProtectorTokenProvider<ApplicationUser>(dataProtectionProvider.Create("ASP.NET Identity"))
                {
                    //Code for email confirmation and reset password life time
                    TokenLifespan = TimeSpan.FromHours(6)
                };
            }
    
            return appUserManager;
        }
    }
    

    and it works finally