C# 多租户应用程序中的IdentityRole

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)

我正在构建一个ASP.NET MVC 5多租户解决方案,在角色方面有一个小问题。我创建了一个自定义角色实体,如下所示:

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);