Search code examples
asp.netasp.net-mvcasp.net-identityasp.net-identity-2

AddToRole and IdentityRole is not part of the model for the current context


I'm using Identity 2.1 to handle the user roles in my asp.net application. So far so good, i created new context extending from IdentityDBContext, extending the IdentityUser and IdentityRole to add a couple of new fields. However, whenever im trying to add a user to a specific role using the UserManager im getting The entity type IdentityRole is not part of the model for the current context.. So there seem to be something wrong with the user-role relationship, here is my code so far for reference:

User

public class User : IdentityUser{

    public string Name { get; set; }
    public async Task<ClaimsIdentity> GenerateUserIdentityAsync(UserManager<User> manager, string authenticationType) {
        // Note the authenticationType must match the one defined in CookieAuthenticationOptions.AuthenticationType
        var userIdentity = await manager.CreateIdentityAsync(this, authenticationType);
        // Add custom user claims here
        return userIdentity;
    }
}

Role

public partial class Role : IdentityRole
{
    public string Description { get; set; }
}

The DB Context

namespace Carbon.Models {

    public partial class CarbonEDM :  IdentityDbContext<User, Role, string, IdentityUserLogin, IdentityUserRole, IdentityUserClaim>{
        public CarbonEDM()
            : base("name=CarbonDB") {
        }

        public static CarbonEDM Create() {
            return new CarbonEDM();
        }

        protected override void OnModelCreating(DbModelBuilder modelBuilder) {

            base.OnModelCreating(modelBuilder);

            modelBuilder.Entity<User>().ToTable("Users", "dbo");
            modelBuilder.Entity<Role>().ToTable("Roles", "dbo");
            modelBuilder.Entity<IdentityUserRole>().ToTable("UserRoles", "dbo");
            modelBuilder.Entity<IdentityUserClaim>().ToTable("UserClaims", "dbo");
            modelBuilder.Entity<IdentityUserLogin>().ToTable("UserLogins", "dbo");
        }
    }
}

ApplicationUserManager

public class ApplicationUserManager : UserManager<User>
{
    public ApplicationUserManager(IUserStore<User> store)
        : base(store)
    {
    }

    public static ApplicationUserManager Create(IdentityFactoryOptions<ApplicationUserManager> options, IOwinContext context) 
    {

        var manager = new ApplicationUserManager(new UserStore<User>(context.Get<CarbonEDM>()));
        // Configure validation logic for usernames
        manager.UserValidator = new UserValidator<User>(manager)
        {
            AllowOnlyAlphanumericUserNames = false,
            RequireUniqueEmail = true
        };

        // Configure validation logic for passwords
        manager.PasswordValidator = new PasswordValidator
        {
            RequiredLength = 6,
            RequireNonLetterOrDigit = false,
            RequireDigit = false,
            RequireLowercase = false,
            RequireUppercase = false,
        };

        // Configure user lockout defaults
        manager.UserLockoutEnabledByDefault = true;
        manager.DefaultAccountLockoutTimeSpan = TimeSpan.FromMinutes(5);
        manager.MaxFailedAccessAttemptsBeforeLockout = 5;

        var dataProtectionProvider = options.DataProtectionProvider;
        if (dataProtectionProvider != null)
        {
            manager.UserTokenProvider = 
                new DataProtectorTokenProvider<User>(dataProtectionProvider.Create("ASP.NET Identity"));
        }
        return manager;
    }
}

And finally, the error am getting whenever im seeding in the migration:

    protected override void Seed(Carbon.Models.CarbonEDM context)
    {

        DbContextTransaction transaction = null;
        transaction = context.Database.BeginTransaction();

        if (!context.Roles.Any()) {
            var roleStore = new RoleStore<Role>(context);
            var roleManager = new RoleManager<Role>(roleStore);

            roleManager.Create(new Role { Name = "Admin" });
            roleManager.Create(new Role { Name = "Control Unit Operator" });
            roleManager.Create(new Role { Name = "Lab Operator" });
            roleManager.Create(new Role { Name = "Production Engineer" });
            roleManager.Create(new Role { Name = "Production Operator" });
        }

        if (!context.Users.Any()) {
            var userStore = new UserStore<User>(context);
            var userManager = new ApplicationUserManager(userStore);

            var _user = new User {
                Email = "yehiasalam@live.com",
                PhoneNumber = "+20 12 23461340",
                Name = "Yehia A.Salam",
                UserName = "yehiasalam@live.com"
            };
            userManager.Create(_user, "pass@word");
            userManager.AddToRole(_user.Id, "Admin"); /* IdentityRole error here */

        }

        context.SaveChanges();
        transaction.Commit();


        base.Seed(context);
    }
}

Sorry for the long post, I tried to include everything.


Solution

  • okay so the problem was with the UserStore, the default declaration was

    public class UserStore<TUser> : UserStore<TUser, IdentityRole, string, IdentityUserLogin, IdentityUserRole, IdentityUserClaim>, IUserStore<TUser>, IUserStore<TUser, string>, IDisposable where TUser : Microsoft.AspNet.Identity.EntityFramework.IdentityUser {
    

    which have IdentityRole explicitly declared instead of making it using the generic notation like TUser, so we just need to create another class extending from the parent UserStore:

    public class CarbonUserStore<TUser> : UserStore<TUser, Role, string, IdentityUserLogin, IdentityUserRole, IdentityUserClaim>, IUserStore<TUser>, IUserStore<TUser, string>, IDisposable where TUser : Microsoft.AspNet.Identity.EntityFramework.IdentityUser {
    
        public CarbonUserStore(DbContext context) :base(context) {}     }
    

    Not cool Microsoft, I spent a day trying to figure it wait. However, it's added in the Identity package shipping with vNext(gotta love it bering open source): https://github.com/aspnet/Identity/blob/dev/src/Microsoft.AspNet.Identity.EntityFramework/UserStore.cs

    public class UserStore<TUser, TRole, TContext> : UserStore<TUser, TRole, TContext, string>
        where TUser : IdentityUser, new()
        where TRole : IdentityRole, new()
        where TContext : DbContext
    {
        public UserStore(TContext context, IdentityErrorDescriber describer = null) : base(context, describer) { }
    }