2017-02-10 15 views
4

Я работаю с Audit.NET, фреймворк аудит с открытым исходным кодом, который обеспечивает расширение для Entity Framework и DbContext здесь: AuditDbContext.csтретьих сторон DbContext, как и реализовать IdentityDbContext

// Implements DbContext public abstract partial class AuditDbContext : DbContext

Я хотел бы реализовать Audit.NET в своем проекте, используя это расширение Entity Framework, потому что он автоматизирует многие шаги, которые мне пришлось бы делать вручную (я могу использовать Audit.NET вручную и без Entity Framework расширение). Проблема, с которой я сталкиваюсь, заключается в том, что мой репозиторий решений реализует IdentityDbContext, который, конечно же, является реализацией DbContext.

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

Там нет существующего AuditDbContext, который реализует IdentityDbContext.

Я не могу думать о чистом виде, чтобы смешать эти два вместе и сделать мое хранилище использовать AuditDbContext, особенно с учетом того, что AuditDbContext защищала конструкторы, и что как DbContext и IdentityDbContext имеют protected метод. Я попытался создать композицию под названием AuditIdentityDbContext, которая имела private копий каждого контекста, но я не могу выполнить все их интерфейсы, сделав это.

Похоже, что все 3 DbContext типам необходимо наследовать из-за членов protected. Впервые в моей карьере я чувствую, что многократное наследование может действительно помочь в этой ситуации, но, учитывая, что это не возможно, какая была бы лучшая альтернатива?

Единственное, что я могу придумать, это создать новый класс, который наследует либо AuditDbContext, либо IdentityDbContext<TUser> и вручную реализует все, что осталось, чтобы соответствовать функциональности другого. В настоящее время классов интерфейса нет, поэтому я уверен, что это не сработает. Я чувствую, что, должно быть, что-то забываю.

ответ

1

Решение @trailmax должно работать, но я обновил библиотеку Audit.NET, чтобы включить поддержку IdentityDbContext.

Предоставляется новый класс AuditIdentityDbContext, чтобы вы могли изменить свой контекст, чтобы наследовать его.

Вы должны изменить свой код:

public class MyDataContext : AuditIdentityDbContext<ApplicationUser> 
{ 
    ... 
} 

Примечание: Я владелец библиотека

GitHub Issue

+1

Вау, большое вам спасибо за ваш быстрый ответ! На самом деле отличный пакет, и я ценю вашу тяжелую работу! – trnelson

1

У меня была аналогичная проблема с проектом, над которым я работал. То, что мы закончили, делало два отдельных DbContext, однако они используют одну и ту же базу данных.

Взгляните на этот ответ, который показывает, как получить доступ к Users и Roles свойства и Claims, Logins и UserRoles от IdentityDbContext

Why is Asp.Net Identity IdentityDbContext a Black-Box?

+0

Спасибо за ваш ответ. Сначала я пошел по этому маршруту и ​​приблизился к завершенной версии, но в итоге реализовал несколько вещей по-другому. Как оказалось, автор пакета получил мою проблему GitHub и сразу же применил ее, чтобы это было связано с моей проблемой. – trnelson

2

Ой!

Но вы все еще можете найти выход. Нет ничего особенного в IdentityDbContext, там даже интерфейса нет! Итак, все, что вам нужно сделать, это рассказать свой собственный 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 

Заменить общие параметры с собственным ApplicationUser и ApplicationRole (оба из этих классов могут наследовать от Идентичность предоставленных классов)

И добавить или смешать с вашим собственные методы:

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

Это должно сделать трюк без необходимости двойного наследования. Viva с открытым исходным кодом!

+1

Большое спасибо за ответ. Это была отличная информация и дал мне много чего попробовать. – trnelson