Anulando SaveChanges y estableciendo ModifiedDate, pero ¿cómo configuro ModifiedBy?

Tengo una aplicación web ASP.NET MVC3 con capas UI, Business (entidades) y Data (DbContext). Estoy utilizando Entity Framework 4.1 Code First. En este momento, estoy anulando el DbContext.SaveChanges() en la capa de datos para que pueda establecer el ModifiedDate para todos los cambios realizados a cualquier objeto de entidad que implemente mi interfaz IAuditable . Tengo una clase y un método DateProvider estáticos (GetCurrentDate) que devuelve DateTime.Now (a menos que esté ejecutando una prueba, en cuyo caso, devuelve lo que le dije).

Me gustaría configurar automáticamente la propiedad ModifiedBy para el usuario actual también. ¿Cuál es la mejor manera de hacer esto? ¿Hay algo construido en el marco que me permita acceder a esta información o tengo que configurar algo así como la clase DateProvider ? Este es un entorno de Active Directory y utilizamos WindowsAuthentication en IIS.

Aquí está mi código SaveChanges:

 public override int SaveChanges() { var changeSet = ChangeTracker.Entries(); if (changeSet != null) { foreach (var entry in changeSet.Where(c => c.State != EntityState.Unchanged)) { entry.Entity.ModifiedDate = DateProvider.GetCurrentDate(); } } return base.SaveChanges(); } 

Puede usar HttpContext.Current.User.Identity.Name para obtener el nombre del usuario actual.

 public override int SaveChanges() { var changeSet = ChangeTracker.Entries(); if (changeSet != null) { foreach (var entry in changeSet.Where(c => c.State != EntityState.Unchanged)) { entry.Entity.ModifiedDate = DateProvider.GetCurrentDate(); entry.Entity.ModifiedBy = HttpContext.Current.User.Identity.Name; } } return base.SaveChanges(); } 

Una mejor forma de hacerlo sería usar la inyección de constructor para pasar al usuario actual al contexto

 public class MyContext : DbContext { public MyContext(string userName) { UserName = userName; } public string UserName { get; private set; } public override int SaveChanges() { var changeSet = ChangeTracker.Entries(); if (changeSet != null) { foreach (var entry in changeSet.Where(c => c.State != EntityState.Unchanged)) { entry.Entity.ModifiedDate = DateProvider.GetCurrentDate(); entry.Entity.ModifiedBy = UserName; } } return base.SaveChanges(); } } 

También quería automatizar la población de campos de auditoría en mi aplicación MVC 4 / Entity Framework 5. Utilicé información de la respuesta de @Eranga y este blog: http://lourenco.co.za/blog/2013/07/audit-trails-concurrency-and-soft-deletion-with-entity-framework/ para que este enfoque funcione para mí con Ninject – publicación en caso de ser valioso para cualquier otra persona:

Creó una interfaz y clase abstracta:

 public interface IAuditableEntity { DateTime? CreatedDate { get; set; } string CreatedBy { get; set; } DateTime? LastModifiedDate { get; set; } string LastModifiedBy { get; set; } } public abstract class AuditableEntity:IAuditableEntity { public DateTime? CreatedDate { get; set; } public string CreatedBy { get; set; } public DateTime? LastModifiedDate { get; set; } public string LastModifiedBy { get; set; } } 

Los usé en mis entidades:

 public class DataEntity : AuditableEntity { public int DataEntityID { get; set; } ... } 

Se agregó un constructor a MyDbContext que aceptó HttpContext y anuló SaveChanges:

 public EFDbContext(HttpContext context) { _context = context; } public HttpContext _context { get; private set; } public override int SaveChanges() { DateTime currentDateTime = DateTime.Now; foreach (var auditableEntity in ChangeTracker.Entries()) { if (auditableEntity.State == EntityState.Added || auditableEntity.State == EntityState.Modified) { auditableEntity.Entity.LastModifiedDate = currentDateTime; switch (auditableEntity.State) { case EntityState.Added: auditableEntity.Entity.CreatedDate = currentDateTime; auditableEntity.Entity.CreatedBy = _context.User.Identity.Name; break; case EntityState.Modified: auditableEntity.Entity.LastModifiedDate = currentDateTime; auditableEntity.Entity.LastModifiedBy = _context.User.Identity.Name; if (auditableEntity.Property(p => p.CreatedDate).IsModified || auditableEntity.Property(p => p.CreatedBy).IsModified) { throw new DbEntityValidationException(string.Format("Attempt to change created audit trails on a modified {0}", auditableEntity.Entity.GetType().FullName)); } break; } } } return base.SaveChanges(); } 

Finalmente, necesita tener un DbContext por solicitud y pasar HttpContext como se indica a continuación en base a esta respuesta: https://stackoverflow.com/a/3617961/1803682 – tenga en cuenta que como MyDbContext ahora es el scope de la Solicitud, los Repositorios también deben estarlo.

 kernel.Bind() .To() .InRequestScope(); kernel.Bind().ToSelf() .InRequestScope() .WithConstructorArgument("context", ninjectContext=>HttpContext.Current);