Third-party implementation of DbContext, how to implement IdentityDbContext

I work with Audit.NET , an open source audit framework that provides an extension for the Entity Framework DbContexthere too: AuditDbContext.cs

// Implements DbContext public abstract partial class AuditDbContext : DbContext

I would like to implement Audit.NET in my project using this Entity Framework extension, because it automates many steps that I otherwise need to do manually (I can use Audit.NET manually and without the Entity Framework extension). The problem I am facing is that my solution repository implements IdentityDbContext, which, of course, is an implementation DbContext.

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

There is no existing AuditDbContextone that implements IdentityDbContext.

It seems that I do not think about how you can mix these two together and make my repository AuditDbContext, especially considering that it AuditDbContexthas protected constructors and that DbContextthey IdentityDbContexthave protected. I tried to create a composition called AuditIdentityDbContextthat had privatecopies of each context, but I cannot execute all their interfaces by doing this.

It seems that all 3 DbContexttypes above should be inherited due to members protected. For the first time in my career, I feel that multiple inheritance can really help in this situation, but given that this is not an opportunity, what would be the best alternative?

, , , AuditDbContext, IdentityDbContext<TUser>, , , . , , . , , , - .

+4
3

@trailmax , Audit.NET, IdentityDbContext.

AuditIdentityDbContext, , .

:

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

.

GitHub

+1

!

. 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 ( , Identity)

:

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

( )

ApplicationUserManager, IUserStore, DbContext, DbContext, AuditDbContext

. Viva !

+2

, . , , DbContext, .

Take a look at this answer, which shows how to access the properties Usersand Roles, and Claims, Loginsand UserRolesfromIdentityDbContext

Why is Asp.Net Identity IdentityDbContext Black-Box?

+1
source

Source: https://habr.com/ru/post/1669415/


All Articles