C# 多租户应用程序中的IdentityRole
我正在构建一个ASP.NET MVC 5多租户解决方案,在角色方面有一个小问题。我创建了一个自定义角色实体,如下所示:C# 多租户应用程序中的IdentityRole,c#,asp.net-mvc,asp.net-mvc-5,asp.net-identity,C#,Asp.net Mvc,Asp.net Mvc 5,Asp.net Identity,我正在构建一个ASP.NET MVC 5多租户解决方案,在角色方面有一个小问题。我创建了一个自定义角色实体,如下所示: public class ApplicationRole : IdentityRole, ITenantEntity { public ApplicationRole() : base() { } public ApplicationRole(string roleName)
public class ApplicationRole : IdentityRole, ITenantEntity
{
public ApplicationRole()
: base()
{
}
public ApplicationRole(string roleName)
: base(roleName)
{
}
public int? TenantId { get; set; }
}
做了所有需要做的事情。。除了一件事之外,一切都很顺利。。。;当租户管理员尝试添加新角色时,如果该角色的名称已被另一租户创建的角色使用,他将收到以下错误:
已使用管理员名称。
显然,在ASP.NET标识的某个地方,角色名是唯一的,这是有一些基础检查的。是否有什么方法可以改变这一点,以便我可以让它通过“TenantId+Name”而不是仅通过Name来寻找唯一性
更新
使用dotPeek反编译DLL,我发现我需要创建自己的IIdentityValidator实现,当然还需要修改我的角色管理器。下面是我的角色验证程序:
public class TenantRoleValidator : IIdentityValidator<ApplicationRole>
{
private RoleManager<ApplicationRole, string> Manager { get; set; }
/// <summary>Constructor</summary>
/// <param name="manager"></param>
public TenantRoleValidator(RoleManager<ApplicationRole, string> manager)
{
if (manager == null)
{
throw new ArgumentNullException("manager");
}
this.Manager = manager;
}
/// <summary>Validates a role before saving</summary>
/// <param name="item"></param>
/// <returns></returns>
public virtual async Task<IdentityResult> ValidateAsync(ApplicationRole item)
{
if ((object)item == null)
{
throw new ArgumentNullException("item");
}
var errors = new List<string>();
await this.ValidateRoleName(item, errors);
return errors.Count <= 0 ? IdentityResult.Success : IdentityResult.Failed(errors.ToArray());
}
private async Task ValidateRoleName(ApplicationRole role, List<string> errors)
{
if (string.IsNullOrWhiteSpace(role.Name))
{
errors.Add("Name cannot be null or empty.");
}
else
{
var existingRole = await this.Manager.Roles.FirstOrDefaultAsync(x => x.TenantId == role.TenantId && x.Name == role.Name);
if (existingRole == null)
{
return;
}
errors.Add(string.Format("{0} is already taken.", role.Name));
}
}
}
这些值不是空的,所以我不知道这里发生了什么。任何帮助都将不胜感激
更新3
我创建了自己的RoleStore,它继承了RoleStore
在继续运行代码之后,我仍然在死亡的黄色屏幕上看到以下错误:
任何人,任何人,请帮助阐明这里发生了什么,以及是否有可能解决这个问题
更新4
好的,我现在更接近答案了。。我从头创建了一个新的db(允许EF创建它),我注意到名称列没有被创建。。。只有Id和租户。。这意味着前面的错误是因为我现有的数据库已经有Name列,并且设置为notnull。。由于某种原因,EF忽略了我的角色实体的Name列,我认为这与它从IdentityRole继承有关
这是我的模型配置:
var rolesTable = modelBuilder.Entity<ApplicationRole>().ToTable("AspNetRoles");
rolesTable.Property(x => x.TenantId)
.HasColumnAnnotation("Index", new IndexAnnotation(new IndexAttribute("RoleNameIndex") { IsUnique = true, Order = 1 }));
rolesTable.Property(x => x.Name)
.IsRequired()
.HasMaxLength(256)
.HasColumnAnnotation("Index", new IndexAnnotation(new IndexAttribute("RoleNameIndex") { IsUnique = true, Order = 2 }));
rolesTable.HasMany(x => x.Users).WithRequired().HasForeignKey(x => x.RoleId);
但是,名称列仍然没有创建。现在和以前的唯一区别是,我使用的是modelBuilder.Entity()
,而默认值应该是modelBuilder.Entity()
如何让EF识别基类中的Name属性、IdentityRole
和派生类ApplicationRole
中的TenantId属性?好的,我已经解决了这个问题。答案是首先跟踪我在原始帖子中添加的所有更新,然后最后要做的事情是让我的ApplicationDbContext
继承自IdentityDbContext
,而不仅仅是IdentityDbContext
好的,我已经解决了这个问题。答案是首先跟踪我在原始帖子中添加的所有更新,然后最后要做的事情是让我的ApplicationDbContext
继承自IdentityDbContext
,而不仅仅是IdentityDbContext
var result = await roleManager.CreateAsync(new ApplicationRole
{
TenantId = tenantId,
Name = role.Name
});
var rolesTable = modelBuilder.Entity<ApplicationRole>().ToTable("AspNetRoles");
rolesTable.Property(x => x.TenantId)
.HasColumnAnnotation("Index", new IndexAnnotation(new IndexAttribute("RoleNameIndex") { IsUnique = true, Order = 1 }));
rolesTable.Property(x => x.Name)
.IsRequired()
.HasMaxLength(256)
.HasColumnAnnotation("Index", new IndexAnnotation(new IndexAttribute("RoleNameIndex") { IsUnique = true, Order = 2 }));
rolesTable.HasMany(x => x.Users).WithRequired().HasForeignKey(x => x.RoleId);
rolesTable.Property(x => x.Name)
.IsRequired()
.HasMaxLength(256);