Why am I getting an IdentityRole error?

2019-02-11 01:07发布

问题:

Using Identity 2.0 After registering a user, the user is created in the database, there is code in the Account controller to create an identity and sign the user in. This is when I get the error. Here is the code producing the error:

var identity = await UserManager.CreateIdentityAsync(user, DefaultAuthenticationTypes.ApplicationCookie);

And here is the error:

The entity type IdentityRole is not part of the model for the current context.

My Model looks like this:

namespace MyApp.Models
{
    public class ApplicationUser : IdentityUser
    {
        [Required]
        [StringLength(50)]
        public string FirstName { get; set; }

        [Required]
        [StringLength(50)]
        public string LastName { get; set; }
    }

    public class ApplicationRole : IdentityRole
    {
        [Required]
        [StringLength(50)]
        public string ProperName { get; set; }

        [Required]
        public string Description { get; set; }
    }


    public class MyAppDb : IdentityDbContext<ApplicationUser, ApplicationRole, string, IdentityUserLogin, IdentityUserRole, IdentityUserClaim>
    {
        public MyAppDb()
            : base("MyAppDb")
        {
        }
    }
}

My UserManager is created like this in the Account controller:

namespace MyApp.Controllers
{
    [Authorize]
    public class AccountController : BaseController
    {
        private UserManager<ApplicationUser> _userManager;

        public AccountController()
        {
        }

        public AccountController(UserManager<ApplicationUser> userManager)
        {
            UserManager = userManager;
        }

        public UserManager<ApplicationUser> UserManager
        {
            get
            {
                return _userManager = new UserManager<ApplicationUser>(new UserStore<ApplicationUser>(new MyAppDb()));
            }
            private set
            {
                _userManager = value;
            }
        }

        ...
    }
}

回答1:

I've spent a lot of time on this issue and posted many questions to get to the bottom of it. I sure hope this information helps other folks.

Basically, customizing the User is easy and there are several examples available. However, customizing the Role is problematic and the only examples I found were customized far beyond what comes "out of the box" and I was able to get one working after resolving an Id issue. The issue in that case was that I had to create the Id myself. Here is that issue: UserManager.Create(user, password) thowing EntityValidationError saying Id is required?

So in simple examples, notice when you are just customizing the User your DbContext inherits from IdentityDbContext and you just provide the IdentityUser, in my case it was called ApplicationUser and looked like this IdentityDbContext<ApplicationUser>. Also notice that the UserManager and UserStore is provided the IdentityUser as well, and in most examples looks like this new UserManager<ApplicationUser>(new UserStore<ApplicationUser>(new ApplicationDbContext()))

But once you customize your Role you need to pass everything, including the key type TKey of the Id fields. Mine looks like this IdentityDbContext<ApplicationUser, ApplicationRole, string, IdentityUserLogin, IdentityUserRole, IdentityUserClaim> because I only customized the User and Role.

But you aren't done yet, because the regular UserManager doesn't understand anymore. I think this is something the Identity folks could/should fix, but I digress. So I had to implement my own UserStore and UserManager and notice (and this is the part that tripped me up) you have to provide the KType here too or instantiating your custom UserManager will give you a compile-time error:

public class ApplicationUserStore : UserStore<ApplicationUser, ApplicationRole, string, IdentityUserLogin, IdentityUserRole, IdentityUserClaim>
{
    public ApplicationUserStore(MyAppDb context)
        : base(context)
    {
    }
}

public class ApplicationUserManager : UserManager<ApplicationUser, string>
{
    public ApplicationUserManager(IUserStore<ApplicationUser, string> store)
        : base(store)
    {
    }
}

And instantiate the UserManager in the Account controller like this new ApplicationUserManager(new ApplicationUserStore(new MyAppDb())):

public class AccountController : BaseController
{
    private ApplicationUserManager _userManager;

    public AccountController()
    {
    }

    public AccountController(ApplicationUserManager userManager)
    {
        UserManager = userManager;
    }

    public ApplicationUserManager UserManager
    {
        get
        {
            return _userManager = new ApplicationUserManager(new ApplicationUserStore(new MyAppDb()));
        }
        private set
        {
            _userManager = value;
        }
    }

    ...

}

Hope this helps!