Reputation: 42380
Because I tend to favour Guid
as my primary key type, my User
and Role
classes are implemented as follows
public class User : IdentityUser<Guid, UserClaim, UserRole, UserLogin>
{
}
public class Role : IdentityRole<Guid, UserRole, RoleClaim>
{
}
Note that UserClaim
, UserRole
, UserLogin
& RoleClaim
are all implemented in the same manner
Here is my DbContext
implementation
public class ApplicationDbContext : IdentityDbContext<User, Role, Guid, UserClaim, UserRole, UserLogin, RoleClaim, UserToken>
{
}
All good so far, except AspNetCore's new DI container doesn't seem to like my custom implementation by default. The following line of code, from my Startup.cs file throws the error shown below
services
.AddIdentity<User, Role>()
.AddEntityFrameworkStores<ApplicationDbContext>()
.AddDefaultTokenProviders();
GenericArguments[0], 'NewCo.DomainModel.Models.Identity.User', on 'Microsoft.AspNetCore.Identity.EntityFrameworkCore.UserStore`4[TUser,TRole,TContext,TKey]' violates the constraint of type 'TUser'.
I am assuming that this is because the default Identity gremlin is implemented to use IdentityUser<string>
, where I'm using IdentityUser<Guid>
.
What do I do next? (I'm all outta ideas)
Note: I'm building against Microsoft's official .NET Core and ASP.NET Core releases as of Monday (June 27th, 2016) and Visual Studio Update 3 (if that's of any help to anyone)
Upvotes: 4
Views: 9238
Reputation: 31
specify Key to .AddEntityFrameworkStore() method in case of using custom User and Role entities.while registering identity in startup
.AddEntityFrameworkStores<IdentityDbContext, TKey>()
because it uses by default key type string and will cause error in case of other key type.
Upvotes: 0
Reputation: 385
I ended up with this solution:
Actually I made my own abstract IdentityDbContext
then you can pass any custom model, the only issue is when creating the db EF adds one Disriminator field to all tables other than user and role(inheritance)
public abstract class ApplicationDbContext<TUser, TRole, TKey, TUserClaim, TUserRole, TUserLogin, TRoleClaim, TUserToken> : IdentityDbContext<TUser, TRole, TKey>
where TUser : IdentityUser<TKey>
where TRole : IdentityRole<TKey>
where TKey : IEquatable<TKey>
where TUserClaim : IdentityUserClaim<TKey>
where TUserRole : IdentityUserRole<TKey>
where TUserLogin : IdentityUserLogin<TKey>
where TRoleClaim : IdentityRoleClaim<TKey>
where TUserToken : IdentityUserToken<TKey>
{
public ApplicationDbContext(DbContextOptions options) : base(options) { }
protected ApplicationDbContext() { }
public new DbSet<TRoleClaim> RoleClaims { get; set; }
public new DbSet<TRole> Roles { get; set; }
public new DbSet<TUserClaim> UserClaims { get; set; }
public new DbSet<TUserLogin> UserLogins { get; set; }
public new DbSet<TUserRole> UserRoles { get; set; }
public new DbSet<TUser> Users { get; set; }
public new DbSet<TUserToken> UserTokens { get; set; }
protected override void OnModelCreating(ModelBuilder builder)
{
base.OnModelCreating(builder);
}
}
public class AppDbContext : ApplicationDbContext<ApplicationUser, ApplicationRole, Guid, ApplicationUserClaim, ApplicationUserRole, ApplicationUserLogin, ApplicationRoleClaim, ApplicationUserToken>
{
public AppDbContext(DbContextOptions<AppDbContext> options)
: base(options)
{
}
//public new DbSet<ApplicationUserClaim> UserClaims { get; set; }
protected override void OnModelCreating(ModelBuilder builder)
{
base.OnModelCreating(builder);
// Customize the ASP.NET Identity model and override the defaults if needed.
// For example, you can rename the ASP.NET Identity table names and more.
// Add your customizations after calling base.OnModelCreating(builder);
}
}
services.AddIdentity<ApplicationUser, ApplicationRole>()
.AddEntityFrameworkStores<AppDbContext, Guid>()
.AddDefaultTokenProviders()
.AddUserStore<UserStore<ApplicationUser, ApplicationRole, AppDbContext, Guid>>()
.AddRoleStore<RoleStore<ApplicationRole, AppDbContext, Guid>>()
public class ApplicationUser : IdentityUser<Guid>
{
public ApplicationUser()
{
//this.Id = Guid.NewGuid();
}
public ApplicationUser(string userName) : this() { this.UserName = userName; }
public Guid ClientId { get; set; }
//public new ICollection<ApplicationUserClaim> Claims { get; set; }
}
//public class ApplicationRole : IdentityRole<Guid, ApplicationUserRole, ApplicationRoleClaim>
public class ApplicationRole : IdentityRole<Guid>
{
public ApplicationRole()
{
//this.Id = Guid.NewGuid();
}
public ApplicationRole(string name) : this() { this.Name = name; }
}
public class ApplicationRoleClaim : IdentityRoleClaim<Guid> { }
//[NotMapped]
public class ApplicationUserClaim : IdentityUserClaim<Guid> { }
public class ApplicationUserLogin : IdentityUserLogin<Guid> { }
public class ApplicationUserRole : IdentityUserRole<Guid> { }
public class ApplicationUserToken : IdentityUserToken<Guid> { }
Upvotes: 5
Reputation: 1527
"UserStore`4[TUser,TRole,TContext,TKey]' violates the constraint of type 'TUser'."
You need to create a UserStore using the Guid, as well as change your DbContext
public class ApplicationUser : IdentityUser<Guid> { }
public class ApplicationRole : IdentityRole<Guid> { }
public class ApplicationUserStore : UserStore<ApplicationUser, ApplicationRole, ApplicationDbContext, Guid>
{
public ApplicationUserStore(ApplicationDbContext context, IdentityErrorDescriber describer = null) : base(context, describer)
{
}
}
New ApplicationDbContext inherit
public class ApplicationDbContext : IdentityDbContext<ApplicationUser, ApplicationRole, Guid>
{
public ApplicationDbContext(DbContextOptions<ApplicationDbContext> options) : base(options) { }
protected override void OnModelCreating(ModelBuilder builder)
{
base.OnModelCreating(builder);
}
}
In your startup.cs
services
.AddIdentity<ApplicationUser, ApplicationRole>()
.AddUserStore<ApplicationUserStore>()
.AddEntityFrameworkStores<ApplicationDbContext, Guid>()
.AddDefaultTokenProviders();
Upvotes: 0
Reputation: 42110
Since you're using a custom key type, you must specify it when calling AddEntityFrameworkStores
:
services
.AddIdentity<User, Role>()
.AddEntityFrameworkStores<ApplicationDbContext, Guid>()
.AddDefaultTokenProviders();
Upvotes: 6