我正在构建一个多租户应用程序。 出于这个原因,我添加了一个名为 OwnerId(角色所有者(的列。 我在使用 ASP.NET 身份向 AspNetRoles 表添加角色时遇到了一些问题。
我有一个自定义的角色验证器,每次评估为成功。但是,保存更改异步失败,并显示: 角色已存在。
我已经更改了 AspNetRoles RoleNameIndex 以适应 Name 和 OwnerId,但是,SaveChangesAsync 仍然失败。
我查看了这个线程,但已经实施了这些更正:标识在多租户应用程序中的角色
应用程序角色存储.cs
using Microsoft.AspNet.Identity;
using Microsoft.AspNet.Identity.EntityFramework;
using MyApp.Models.Identity.Context;
using System;
using System.Collections.Generic;
using System.Data.Entity;
using System.Data.Entity.Validation;
using System.Linq;
using System.Threading.Tasks;
using System.Web;
namespace MyApp.Models.Identity
{
public class ApplicationRoleStore : RoleStore<ApplicationRole, string, ApplicationUserRole>
{
private EntityStore<ApplicationRole> _roleStore;
public ApplicationRoleStore(ApplicationDbContext context)
: base(context)
{
_roleStore = new EntityStore<ApplicationRole>(context);
}
public IQueryable<ApplicationRole> GetStandardRoles()
{
var roles = Roles.AsNoTracking().Where(x => x.IsAdminRole == false && x.BaseRoleId == "");
return (roles);
}
public IQueryable<ApplicationRole> GetTenantRoles(string ownerId)
{
var roles = Roles.AsNoTracking().Where(x => x.OwnerId == ownerId);
return (roles);
}
public override async Task CreateAsync(ApplicationRole role)
{
if (role == null)
{
throw new ArgumentNullException("role");
}
if (String.IsNullOrEmpty(role.Id))
{
role.Id = Guid.NewGuid().ToString().ToLower();
}
_roleStore.Create(role);
try
{
await Context.SaveChangesAsync().WithCurrentCulture();
}
catch (DbEntityValidationException e)
{
EntityValidationErrors.DisplayErrors(e);
throw;
}
}
}
}
ApplicationRoleValidator.cs
using Microsoft.AspNet.Identity;
using System;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using System.Resources;
using System.Threading.Tasks;
using System.Web;
namespace MyApp.Models.Identity
{
public class ApplicationRoleValidator : RoleValidator<ApplicationRole, string>
{
public ApplicationRoleValidator(ApplicationRoleManager manager) : base(manager)
{
Manager = manager;
}
private ApplicationRoleManager Manager { get; set; }
public override async Task<IdentityResult> ValidateAsync(ApplicationRole item)
{
if (item == null)
{
throw new ArgumentNullException("item");
}
var errors = new List<string>();
await ValidateRoleName(item, errors).WithCurrentCulture();
if (errors.Count > 0)
{
return IdentityResult.Failed(errors.ToArray());
}
return IdentityResult.Success;
}
private async Task ValidateRoleName(ApplicationRole role, List<string> errors)
{
if (string.IsNullOrWhiteSpace(role.Name))
{
errors.Add(String.Format(CultureInfo.CurrentCulture, Resources.PropertyTooShort, "Name"));
}
else
{
var owner = Manager.FindByNameAndOwner(role.Name, role.OwnerId);
if (owner != null && !EqualityComparer<string>.Default.Equals(owner.Id, role.Id))
{
errors.Add(String.Format(CultureInfo.CurrentCulture, Resources.DuplicateName, role.Name));
}
}
}
}
}
应用程序角色.cs
using Microsoft.AspNet.Identity;
using Microsoft.AspNet.Identity.EntityFramework;
using System.Threading.Tasks;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.ComponentModel.DataAnnotations.Schema;
namespace MyApp.Models.Identity
{
public class ApplicationRole : IdentityRole<string, ApplicationUserRole>
{
public ApplicationRole() : base()
{
}
public ApplicationRole(string name) : this()
{
base.Name = name;
}
public ApplicationRole(string name, string ownerId) : this(name)
{
OwnerId = ownerId;
}
public ApplicationRole(string name, string description, string ownerId) : this(name, "", description, ownerId)
{
}
public ApplicationRole(string name, string addrv, string description, string ownerId, string baseRoleId = "") : this(name, ownerId)
{
Abbrv = addrv;
Description = description;
BaseRoleId = baseRoleId;
}
public string Abbrv { get; set; }
public string Description { get; set; }
public int Order { get; set; } = 0;
public bool IsAdminRole { get; set; } = false;
public string OwnerId { get; set; }
[ForeignKey("OwnerId")]
public virtual ApplicationUser Owner { get; set; }
public string BaseRoleId { get; set; }
[ForeignKey("BaseRoleId")]
public virtual ApplicationRole BaseRole { get; set; }
}
}
ApplicationDbContext.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using Microsoft.AspNet.Identity;
using Microsoft.AspNet.Identity.EntityFramework;
using MyApp.Models.Identity;
using System.Threading.Tasks;
using System.Data.Entity;
using System.Security.Claims;
using System.ComponentModel.DataAnnotations.Schema;
using System.Data.Entity.Infrastructure.Annotations;
namespace MyApp.Models.Identity.Context
{
public class ApplicationDbContext : IdentityDbContext<ApplicationUser, ApplicationRole, string, IdentityUserLogin, ApplicationUserRole, IdentityUserClaim>
{
public ApplicationDbContext()
: base("DefaultConnection")
{
base.Configuration.ProxyCreationEnabled = false;
}
static ApplicationDbContext()
{
// Set the database intializer which is run once during application start
// This seeds the database with admin user credentials and admin role
//Database.SetInitializer<ApplicationDbContext>(new ApplicationDbInitializer());
}
public static ApplicationDbContext Create()
{
ApplicationDbContext context = new ApplicationDbContext();
context.Database.Initialize(true);
return context;
}
//public virtual DbSet<ApplicationUser> Users { get; set; }
//public virtual DbSet<ApplicationRole> Roles { get; set; }
public virtual DbSet<UserDetail> UserDetails { get; set; }
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
base.OnModelCreating(modelBuilder);
//modelBuilder.Entity<ApplicationUser>().HasMany<ApplicationUserRole>((ApplicationUser u) => u.Roles);
modelBuilder.Entity<ApplicationUser>()
.ToTable("AspNetUsers");
var role = modelBuilder.Entity<ApplicationRole>()
.ToTable("AspNetRoles");
role.Property(r => r.Name)
.IsRequired()
.HasMaxLength(256)
.HasColumnAnnotation("Index", new IndexAnnotation(
new IndexAttribute("RoleNameIndex", 1)
{ IsUnique = true }));
role.Property(r => r.OwnerId)
.IsRequired()
.HasMaxLength(128)
.HasColumnAnnotation("Index", new IndexAnnotation(
new IndexAttribute("RoleNameIndex", 2)
{ IsUnique = true }));
modelBuilder.Entity<ApplicationUserRole>().HasKey((ApplicationUserRole r) =>
new { UserId = r.UserId, RoleId = r.RoleId }).ToTable("AspNetUserRoles");
}
}
}
我的解决方案是添加ApplicationDbContext:
protected override DbEntityValidationResult ValidateEntity(DbEntityEntry entityEntry, IDictionary<object, object> items)
{
var res = base.ValidateEntity(entityEntry, items);
//hack to convince EF that AspNetRole.Name does not need to be unique
if (!res.IsValid
&& entityEntry.Entity is ApplicationRole
&& entityEntry.State == EntityState.Added
&& res.ValidationErrors.Count == 1
&& res.ValidationErrors.First().PropertyName == "Role")
{
return new DbEntityValidationResult(entityEntry, new List<DbValidationError>());
}
return res;
}