Search code examples
c#asp.net-mvcentity-frameworkasp.net-mvc-4asp.net-identity-3

Integrating & Extending .NET Identity Classes in EF (Code first)


I am starting an entirely new .NET MVC project, using code-first against EF 6 and .NET 4.5. I want to use Identity framework also, and extend the Identity base classes within the context configuration for my project. (Not sure I am stating that all correctly... I am a seasoned C#/.NET developer that's somewhat new to MVC, EF, and Identity.)

My problem: something's quite wrong. In attempting to generate a new migration, I am getting errors:

POST.Data.Models.IdentityUserLogin: : EntityType 'IdentityUserLogin' has no key defined. Define the key for this EntityType.
POST.Data.Models.IdentityUserRole: : EntityType 'IdentityUserRole' has no key defined. Define the key for this EntityType.
IdentityUserLogins: EntityType: EntitySet 'IdentityUserLogins' is based on type 'IdentityUserLogin' that has no keys defined.
IdentityUserRoles: EntityType: EntitySet 'IdentityUserRoles' is based on type 'IdentityUserRole' that has no keys defined.

Okay, so, I have two contexts in my project, one for the Identity classes, the other for everything else. Same database, and nothing from either of the contexts refers to anything in the other. I define the entities thusly:

public class ApplicationUser : IdentityUser { }
public class ApplicationRole : IdentityRole { }
public class ApplicationUserRole : IdentityUserRole { }
public class ApplicationUserClaim : IdentityUserClaim { }
public class ApplicationUserLogin : IdentityUserLogin { }

Then, I have a context class like this:

public partial class IdentityContext : IdentityDbContext
{
    public IdentityContext() : base() { }

    protected override void OnModelCreating(DbModelBuilder modelBuilder)
    {
        base.OnModelCreating(modelBuilder);
        modelBuilder.Entity<IdentityUserLogin>().HasKey<string>(ul => ul.UserId);
        modelBuilder.Entity<IdentityRole>().HasKey<string>(r => r.Id);
        modelBuilder.Entity<IdentityUserRole>().HasKey(ur => new { ur.RoleId, ur.UserId });
    }

    public DbSet<ApplicationUser> ApplicationUsers { get; set; }
    public DbSet<ApplicationUserClaim> ApplicationUserClaims { get; set; }
    public DbSet<ApplicationUserLogin> ApplicationUserLogins { get; set; }
    public DbSet<ApplicationRole> ApplicationRoles { get; set; }
    public DbSet<ApplicationUserRole> ApplicationUserRoles { get; set; }
}

Not sure it even matters, but my configuration thing looks like this:

internal sealed class Configuration : DbMigrationsConfiguration<POST.Data.Models.Context>
{
    public Configuration()
    {
        AutomaticMigrationsEnabled = false;
        MigrationsDirectory = @"ContextMigrations";
    }

    protected override void Seed(POST.Data.Models.Context context) {}
}

That will build, but I can't generate the migration without those errors, and with my limited knowledge and understanding of all the details, I'm baffled.


Solution

  • Since you're not extending any of the identity entities for user, role etc I wouldn't bother creating your own identity subclasses (ApplicationUser, ApplicationRole, etc). You also don't need to define any identity related DbSets on your context as they're automatically inherited from IdentityDbContext. However if you want to keep your identity subclasses your DbContext should inherit from the generic IdentityDbContext as this allows you to define your custom identity entities:

    public class IdentityContext : IdentityDbContext<ApplicationUser, ApplicationRole, string, ApplicationUserLogin, ApplicationUserRole, ApplicationUserClaim>
    {
       // Define other non-identity related dbsets
    }
    

    This will ensure your DbContext automatically has all of the relevant DbSet properties without having to explicitly define them as they're inherited from the generic IdentityDbContext<> class.

    You also shouldn't need to define any migrations or fluent api configuration in the OnModelCreating for any of the identity stuff since you're not adding anything to the identity entities (e.g. additional ApplicationUser properties). The default identity tables will be created automatically when the DbContext/EF is initialised.