Hi, I would like to customize IdentityDbContext with my own implemention but I got an error why ?
error message : Cannot use table 'AspNetRoleClaims' in schema '' for entity 'AspNetRoleClaims' since it is being used for another entity
public class MyIdentityDbContext : IdentityDbContext<MyUser> { public virtual DbSet<AspNetRoleClaims> AspNetRoleClaims { get; set; } public virtual DbSet<AspNetRoles> AspNetRoles { get; set; } public virtual DbSet<AspNetUserClaims> AspNetUserClaims { get; set; } public virtual DbSet<AspNetUserLogins> AspNetUserLogins { get; set; } public virtual DbSet<AspNetUserRoles> AspNetUserRoles { get; set; } public virtual DbSet<AspNetUserTokens> AspNetUserTokens { get; set; } public virtual DbSet<AspNetUsers> AspNetUsers { get; set; } public MyIdentityDbContext(DbContextOptions<MyIdentityDbContext> options) : base(options) { } protected override void OnModelCreating(ModelBuilder modelBuilder) { base.OnModelCreating(modelBuilder); modelBuilder.Entity<AspNetRoleClaims>(entity => { entity.HasIndex(e => e.RoleId) .HasName("IX_AspNetRoleClaims_RoleId"); entity.Property(e => e.RoleId) .IsRequired() .HasMaxLength(450); entity.HasOne(d => d.Role) .WithMany(p => p.AspNetRoleClaims) .HasForeignKey(d => d.RoleId); }); modelBuilder.Entity<AspNetRoles>(entity => { entity.HasIndex(e => e.NormalizedName) .HasName("RoleNameIndex"); entity.Property(e => e.Id).HasMaxLength(450); entity.Property(e => e.Name).HasMaxLength(256); entity.Property(e => e.NormalizedName).HasMaxLength(256); }); modelBuilder.Entity<AspNetUserClaims>(entity => { entity.HasIndex(e => e.UserId) .HasName("IX_AspNetUserClaims_UserId"); entity.Property(e => e.UserId) .IsRequired() .HasMaxLength(450); entity.HasOne(d => d.User) .WithMany(p => p.AspNetUserClaims) .HasForeignKey(d => d.UserId); }); modelBuilder.Entity<AspNetUserLogins>(entity => { entity.HasKey(e => new { e.LoginProvider, e.ProviderKey }) .HasName("PK_AspNetUserLogins"); entity.HasIndex(e => e.UserId) .HasName("IX_AspNetUserLogins_UserId"); entity.Property(e => e.LoginProvider).HasMaxLength(450); entity.Property(e => e.ProviderKey).HasMaxLength(450); entity.Property(e => e.UserId) .IsRequired() .HasMaxLength(450); entity.HasOne(d => d.User) .WithMany(p => p.AspNetUserLogins) .HasForeignKey(d => d.UserId); }); modelBuilder.Entity<AspNetUserRoles>(entity => { entity.HasKey(e => new { e.UserId, e.RoleId }) .HasName("PK_AspNetUserRoles"); entity.HasIndex(e => e.RoleId) .HasName("IX_AspNetUserRoles_RoleId"); entity.HasIndex(e => e.UserId) .HasName("IX_AspNetUserRoles_UserId"); entity.Property(e => e.UserId).HasMaxLength(450); entity.Property(e => e.RoleId).HasMaxLength(450); entity.HasOne(d => d.Role) .WithMany(p => p.AspNetUserRoles) .HasForeignKey(d => d.RoleId); entity.HasOne(d => d.User) .WithMany(p => p.AspNetUserRoles) .HasForeignKey(d => d.UserId); }); modelBuilder.Entity<AspNetUserTokens>(entity => { entity.HasKey(e => new { e.UserId, e.LoginProvider, e.Name }) .HasName("PK_AspNetUserTokens"); entity.Property(e => e.UserId).HasMaxLength(450); entity.Property(e => e.LoginProvider).HasMaxLength(450); entity.Property(e => e.Name).HasMaxLength(450); }); modelBuilder.Entity<AspNetUsers>(entity => { entity.HasIndex(e => e.NormalizedEmail) .HasName("EmailIndex"); entity.HasIndex(e => e.NormalizedUserName) .HasName("UserNameIndex") .IsUnique(); entity.Property(e => e.Id).HasMaxLength(450); entity.Property(e => e.Email).HasMaxLength(256); entity.Property(e => e.NormalizedEmail).HasMaxLength(256); entity.Property(e => e.NormalizedUserName) .IsRequired() .HasMaxLength(256); entity.Property(e => e.UserName).HasMaxLength(256); }); } }
public class MyUserStore : IUserStore<MyUser>, IUserPasswordStore<MyUser>, IUserLoginStore<MyUser>, IUserEmailStore<MyUser>, IUserRoleStore<MyUser>, IUserClaimStore<MyUser> { private readonly IUserRepository<MyUser> _userRepository; private readonly IRoleRepository<MyRole> _roleRepository; public MyUserStore(IUserRepository<MyUser> userRepository, IRoleRepository<MyRole> roleRepository) { _userRepository = userRepository; _roleRepository = roleRepository; } public async Task AddClaimsAsync(MyUser user, IEnumerable<Claim> claims, CancellationToken cancellationToken) { await Task.Run(() => { foreach (var claim in claims) { user.Claims.Add(new Microsoft.AspNetCore.Identity.EntityFrameworkCore.IdentityUserClaim<string> { ClaimType = claim.Type, ClaimValue = claim.Value, UserId = user.Id }); } } ); } public Task AddLoginAsync(MyUser user, UserLoginInfo login, CancellationToken cancellationToken) { throw new NotImplementedException(); } public async Task AddToRoleAsync(MyUser user, string roleName, CancellationToken cancellationToken) { await _roleRepository.AddToRoleAsync(user.Id, roleName); } public async Task<IdentityResult> CreateAsync(MyUser user, CancellationToken cancellationToken) { if (user == null) { throw new ArgumentNullException("user"); } return await _userRepository.CreateAsync(user); } public Task<IdentityResult> DeleteAsync(MyUser user, CancellationToken cancellationToken) { throw new NotImplementedException(); } public void Dispose() { //throw new NotImplementedException(); } public Task<MyUser> FindByEmailAsync(string normalizedEmail, CancellationToken cancellationToken) { throw new NotImplementedException(); } public Task<MyUser> FindByIdAsync(string userId, CancellationToken cancellationToken) { throw new NotImplementedException(); } public Task<MyUser> FindByLoginAsync(string loginProvider, string providerKey, CancellationToken cancellationToken) { throw new NotImplementedException(); } public async Task<MyUser> FindByNameAsync(string normalizedUserName, CancellationToken cancellationToken) { if (string.IsNullOrEmpty(normalizedUserName)) { throw new ArgumentException("Null or empty argument: userName"); } return await _userRepository.FindByNameAsync(normalizedUserName); } public async Task<IList<Claim>> GetClaimsAsync(MyUser user, CancellationToken cancellationToken) { if (user == null) { throw new ArgumentException("Null or empty argument: user"); } return await _userRepository.GetClaimsAsync(user.Id); } public async Task<string> GetEmailAsync(MyUser user, CancellationToken cancellationToken) { if (user == null) { throw new ArgumentException("Null or empty argument: user"); } return await Task.FromResult(user.Email); //return await _userRepository.GetEmailAsync(user.Id); } public Task<bool> GetEmailConfirmedAsync(MyUser user, CancellationToken cancellationToken) { throw new NotImplementedException(); } public Task<IList<UserLoginInfo>> GetLoginsAsync(MyUser user, CancellationToken cancellationToken) { throw new NotImplementedException(); } public Task<string> GetNormalizedEmailAsync(MyUser user, CancellationToken cancellationToken) { throw new NotImplementedException(); } public Task<string> GetNormalizedUserNameAsync(MyUser user, CancellationToken cancellationToken) { throw new NotImplementedException(); } public async Task<string> GetPasswordHashAsync(MyUser user, CancellationToken cancellationToken) { return await _userRepository.GetPasswordHashAsync(user); } public async Task<IList<string>> GetRolesAsync(MyUser user, CancellationToken cancellationToken) { if (user == null) { throw new ArgumentException("Null or empty argument: user"); } return await _userRepository.GetRolesAsync(user.Id); } public async Task<string> GetUserIdAsync(MyUser user, CancellationToken cancellationToken) { if (user == null) { throw new ArgumentException("Null or empty argument: user"); } return await Task.FromResult(user.Id); } public async Task<string> GetUserNameAsync(MyUser user, CancellationToken cancellationToken) { if (user == null) { throw new ArgumentException("Null or empty argument: user"); } return await Task.FromResult(user.UserName ?? user.NormalizedUserName); } public Task<IList<MyUser>> GetUsersForClaimAsync(Claim claim, CancellationToken cancellationToken) { throw new NotImplementedException(); } public Task<IList<MyUser>> GetUsersInRoleAsync(string roleName, CancellationToken cancellationToken) { throw new NotImplementedException(); } public Task<bool> HasPasswordAsync(MyUser user, CancellationToken cancellationToken) { throw new NotImplementedException(); } public async Task<bool> IsInRoleAsync(MyUser user, string roleName, CancellationToken cancellationToken) { //return await _userRepository.GetRolesAsync(user.Id); return false; } public Task RemoveClaimsAsync(MyUser user, IEnumerable<Claim> claims, CancellationToken cancellationToken) { throw new NotImplementedException(); } public Task RemoveFromRoleAsync(MyUser user, string roleName, CancellationToken cancellationToken) { throw new NotImplementedException(); } public Task RemoveLoginAsync(MyUser user, string loginProvider, string providerKey, CancellationToken cancellationToken) { throw new NotImplementedException(); } public Task ReplaceClaimAsync(MyUser user, Claim claim, Claim newClaim, CancellationToken cancellationToken) { throw new NotImplementedException(); } public Task SetEmailAsync(MyUser user, string email, CancellationToken cancellationToken) { throw new NotImplementedException(); } public Task SetEmailConfirmedAsync(MyUser user, bool confirmed, CancellationToken cancellationToken) { throw new NotImplementedException(); } public async Task SetNormalizedEmailAsync(MyUser user, string normalizedEmail, CancellationToken cancellationToken) { await Task.Run(() => user.NormalizedEmail = normalizedEmail); } public async Task SetNormalizedUserNameAsync(MyUser user, string normalizedName, CancellationToken cancellationToken) { await Task.Run(() => user.NormalizedUserName = normalizedName); } public async Task SetPasswordHashAsync(MyUser user, string passwordHash, CancellationToken cancellationToken) { await Task.Run(() => user.PasswordHash = passwordHash); } public async Task SetUserNameAsync(MyUser user, string userName, CancellationToken cancellationToken) { await Task.Run(() => user.UserName = userName); } public async Task<IdentityResult> UpdateAsync(MyUser user, CancellationToken cancellationToken) { if (user == null) { throw new ArgumentException("Null or empty argument: user"); } return await _userRepository.UpdateAsync(user); } }
public class MyRoleStore : IRoleStore<MyRole> { #region IRoleStore private readonly IRoleRepository<MyRole> _roleRepository; public MyRoleStore(IRoleRepository<MyRole> roleRepository) { _roleRepository = roleRepository; } /// <summary> /// Create a new role /// </summary> /// <param name="role"></param> /// <param name="cancellationToken"></param> /// <returns></returns> public async Task<IdentityResult> CreateAsync(MyRole role, CancellationToken cancellationToken) { if (role == null) { var error = new IdentityError { Code = "1", Description = "Role cannot be null" }; return IdentityResult.Failed(error); } await _roleRepository.CreateAsync(role); return IdentityResult.Success; } /// <summary> /// Delete a role /// </summary> /// <param name="role"></param> /// <param name="cancellationToken"></param> /// <returns></returns> public async Task<IdentityResult> DeleteAsync(MyRole role, CancellationToken cancellationToken) { if (role == null) { var error = new IdentityError { Code = "1", Description = "Role cannot be null" }; return IdentityResult.Failed(error); } await _roleRepository.DeleteAsync(role.Id); return IdentityResult.Success; } /// <summary> /// Dispose service /// </summary> public void Dispose() { //throw new NotImplementedException(); } /// <summary> /// Find a role by id /// </summary> /// <param name="roleId"></param> /// <param name="cancellationToken"></param> /// <returns></returns> public Task<MyRole> FindByIdAsync(string roleId, CancellationToken cancellationToken) { throw (new NotImplementedException()); } /// <summary> /// Find a role by name /// </summary> /// <param name="normalizedRoleName"></param> /// <param name="cancellationToken"></param> /// <returns></returns> public async Task<MyRole> FindByNameAsync(string normalizedRoleName, CancellationToken cancellationToken) { return await _roleRepository.FindByNameAsync(normalizedRoleName); } /// <summary> /// Find a role by normalized role name /// </summary> /// <param name="role"></param> /// <param name="cancellationToken"></param> /// <returns></returns> public Task<string> GetNormalizedRoleNameAsync(MyRole role, CancellationToken cancellationToken) { return Task.FromResult(role.Name.ToUpper()); } /// <summary> /// Get id of a role /// </summary> /// <param name="role"></param> /// <param name="cancellationToken"></param> /// <returns></returns> public Task<string> GetRoleIdAsync(MyRole role, CancellationToken cancellationToken) { return Task.FromResult(role.Id.ToString()); } /// <summary> /// Get name of a role /// </summary> /// <param name="role"></param> /// <param name="cancellationToken"></param> /// <returns></returns> public Task<string> GetRoleNameAsync(MyRole role, CancellationToken cancellationToken) { return Task.FromResult(role.Name); } /// <summary> /// Set normalized name for a role /// </summary> /// <param name="role"></param> /// <param name="normalizedName"></param> /// <param name="cancellationToken"></param> /// <returns></returns> public async Task SetNormalizedRoleNameAsync(MyRole role, string normalizedName, CancellationToken cancellationToken) { await Task.Run(() => role.NormalizedName = normalizedName); } /// <summary> /// Set name for a role /// </summary> /// <param name="role"></param> /// <param name="roleName"></param> /// <param name="cancellationToken"></param> /// <returns></returns> public async Task SetRoleNameAsync(MyRole role, string roleName, CancellationToken cancellationToken) { await Task.Run(() => role.Name = roleName); } /// <summary> /// Update an existing role /// </summary> /// <param name="role"></param> /// <param name="cancellationToken"></param> /// <returns></returns> public Task<IdentityResult> UpdateAsync(MyRole role, CancellationToken cancellationToken) { throw new NotImplementedException(); } #endregion }
public class MyUser : IdentityUser { }
public class MyRole : IdentityRole { }
// This method gets called by the runtime. Use this method to add services to the container. public void ConfigureServices(IServiceCollection services) { services.AddSingleton(Configuration); // Add framework services. services.AddMvc(); services.AddDbContext<MyIdentityDbContext>(options => options.UseSqlServer(Configuration.GetConnectionString("SecurityConnection"), sqlOptions => sqlOptions.MigrationsAssembly("MySample.WebApi.Core"))); services.AddIdentity<MyUser, MyRole>(cfg => { // if we are accessing the /api and an unauthorized request is made // do not redirect to the login page, but simply return "Unauthorized" cfg.Cookies.ApplicationCookie.Events = new CookieAuthenticationEvents { OnRedirectToLogin = ctx => { if (ctx.Request.Path.StartsWithSegments("/api")) ctx.Response.StatusCode = (int)System.Net.HttpStatusCode.Unauthorized; return Task.FromResult(0); } }; }).AddEntityFrameworkStores<MyIdentityDbContext>() .AddDefaultTokenProviders(); services.AddScoped<IUserRepository<MyUser>, UserRepository>(); services.AddScoped<IRoleRepository<MyRole>, RoleRepository>(); services.AddScoped<IRoleStore<MyRole>, MyRoleStore>(); services.AddScoped<IUserStore<MyUser>, MyUserStore>(); }
But I have an error at runtime:
The exception occurs in MyUserRepository : databaseContext.AspNetUsers.SingleOrDefault(u => u.UserName == normalizedUserName);
public async Task<MyUser> FindByNameAsync(string normalizedUserName) { return await Task.Run(() => { var user = _databaseContext.AspNetUsers.SingleOrDefault(u => u.UserName == normalizedUserName);
How to use it correctly ?
Regards