c# - DbContext的第三方实现,如何同时实现IdentityDbContext

标签 c# entity-framework asp.net-identity dbcontext audit.net

我正在使用 Audit.NET ,一个开源审计框架,它为 Entity Framework 和 DbContext 提供扩展这里:AuditDbContext.cs

// Implements DbContext public abstract partial class AuditDbContext : DbContext

我想在我的项目中使用这个 Entity Framework 扩展实现 Audit.NET,因为它会自动执行很多我需要手动执行的步骤(我可以手动使用 Audit.NET,无需 Entity Framework 扩展)。我遇到的问题是我的解决方案存储库实现了 IdentityDbContext这当然是 DbContext 的实现还有。

// Implements IdentityDbContext public class MyDataContext : IdentityDbContext<ApplicationUser> { public MyDataContext() : base("DefaultConnection") { } ...

不存在AuditDbContext实现 IdentityDbContext .

我似乎想不出一种干净的方法来将这两者混合在一起并让我的存储库使用 AuditDbContext ,特别是考虑到 AuditDbContext有 protected 构造函数,而且这两个 DbContextIdentityDbContextprotected方法。我试图创建一个名为 AuditIdentityDbContext 的组合那有 private每个上下文的副本,但我无法通过这样做来实现它们的所有接口(interface)。

似乎所有 3 DbContext由于 protected 需要继承上述类型成员。在我的职业生涯中,我第一次觉得多重继承在这种情况下实际上可能有所帮助,但鉴于这不可能,最好的选择是什么?

我唯一能想到的就是创建一个继承自 AuditDbContext 的新类或 IdentityDbContext<TUser>并手动实现剩下的任何东西以匹配另一个的功能。虽然没有要实现的接口(interface)类,所以我很确定这是行不通的。我觉得我一定是忽略了什么。

最佳答案

哎哟!

但你还是可以找到出路的。 IdentityDbContext 没有什么特别之处,甚至没有接口(interface)!所以您需要做的就是告诉您自己的 DbContext 有关用户和角色的信息并添加一些验证。

IdentityDbContext 的内容是这样的:

    public virtual IDbSet<TUser> Users { get; set; }

    public virtual IDbSet<TRole> Roles { get; set; }

    public bool RequireUniqueEmail { get; set; } // this might not be important for you

用您自己的 ApplicationUserApplicationRole 替换通用参数(这两个类都可以继承自 Identity-provided 类)

并添加或混合您自己的方法:

    protected override void OnModelCreating(DbModelBuilder modelBuilder)
    {
        if (modelBuilder == null)
        {
            throw new ArgumentNullException("modelBuilder");
        }

        // Needed to ensure subclasses share the same table
        var user = modelBuilder.Entity<TUser>()
            .ToTable("AspNetUsers");
        user.HasMany(u => u.Roles).WithRequired().HasForeignKey(ur => ur.UserId);
        user.HasMany(u => u.Claims).WithRequired().HasForeignKey(uc => uc.UserId);
        user.HasMany(u => u.Logins).WithRequired().HasForeignKey(ul => ul.UserId);
        user.Property(u => u.UserName)
            .IsRequired()
            .HasMaxLength(256)
            .HasColumnAnnotation("Index", new IndexAnnotation(new IndexAttribute("UserNameIndex") { IsUnique = true }));

        // CONSIDER: u.Email is Required if set on options?
        user.Property(u => u.Email).HasMaxLength(256);

        modelBuilder.Entity<TUserRole>()
            .HasKey(r => new { r.UserId, r.RoleId })
            .ToTable("AspNetUserRoles");

        modelBuilder.Entity<TUserLogin>()
            .HasKey(l => new { l.LoginProvider, l.ProviderKey, l.UserId })
            .ToTable("AspNetUserLogins");

        modelBuilder.Entity<TUserClaim>()
            .ToTable("AspNetUserClaims");

        var role = modelBuilder.Entity<TRole>()
            .ToTable("AspNetRoles");
        role.Property(r => r.Name)
            .IsRequired()
            .HasMaxLength(256)
            .HasColumnAnnotation("Index", new IndexAnnotation(new IndexAttribute("RoleNameIndex") { IsUnique = true }));
        role.HasMany(r => r.Users).WithRequired().HasForeignKey(ur => ur.RoleId);
    }

    protected override DbEntityValidationResult ValidateEntity(DbEntityEntry entityEntry,
        IDictionary<object, object> items)
    {
        if (entityEntry != null && entityEntry.State == EntityState.Added)
        {
            var errors = new List<DbValidationError>();
            var user = entityEntry.Entity as TUser;
            //check for uniqueness of user name and email
            if (user != null)
            {
                if (Users.Any(u => String.Equals(u.UserName, user.UserName)))
                {
                    errors.Add(new DbValidationError("User",
                        String.Format(CultureInfo.CurrentCulture, IdentityResources.DuplicateUserName, user.UserName)));
                }
                if (RequireUniqueEmail && Users.Any(u => String.Equals(u.Email, user.Email)))
                {
                    errors.Add(new DbValidationError("User",
                        String.Format(CultureInfo.CurrentCulture, IdentityResources.DuplicateEmail, user.Email)));
                }
            }
            else
            {
                var role = entityEntry.Entity as TRole;
                //check for uniqueness of role name
                if (role != null && Roles.Any(r => String.Equals(r.Name, role.Name)))
                {
                    errors.Add(new DbValidationError("Role",
                        String.Format(CultureInfo.CurrentCulture, IdentityResources.RoleAlreadyExists, role.Name)));
                }
            }
            if (errors.Any())
            {
                return new DbEntityValidationResult(entityEntry, errors);
            }
        }
        return base.ValidateEntity(entityEntry, items);
    }

(taken from source code as is)

当您需要创建 ApplicationUserManager 时,它需要 IUserStore 并且用户存储的默认实现需要 DbContext 因此您可以提供自己的 DbContext实际上继承自 AuditDbContext

这应该可以解决问题,而不必双重继承。开源万岁!

关于c# - DbContext的第三方实现,如何同时实现IdentityDbContext,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/42168013/

相关文章:

asp.net - 如何从 ASP.NET Identity 获取用户列表?

c# - Attribute.Add on MasterPage <body> 标签

c# - 无法使用 MvxBind 设置 BackgroundColor

c# - 具有 ComplexType 的 BulkInsert 实体

asp.net-identity - ASP.net identity 是否使用 open id connect?

asp.net-identity - 调用 SignIn 后是否可以使用 OWIN 修改 ASP.NET Identity 中的声明?

c# - 检查字符串是否包含多个空格

c# - .net 的 S/MIME 库?

c# - Entity Framework 查询 super 慢

c# - 带有 XML 文件的 Entity Framework