我有一个带有UI,业务(实体)和数据(DbContext)层的ASP.NET MVC3 Web应用程序。我正在使用Entity Framework 4.1 Code First。现在,我正在覆盖数据层中的DbContext.SaveChanges()
,以便我可以为实现我的ModifiedDate
接口的任何实体对象的所有更改设置IAuditable
。我有一个返回DateProvider
的静态DateTime.Now
类和方法(GetCurrentDate)(除非我正在运行测试,在这种情况下,它会返回我告诉它的任何内容)。
我想自动将ModifiedBy
属性设置为当前用户。这样做的最佳方法是什么?框架中是否有一些内容可以让我访问这些信息,或者我需要设置类似于DateProvider
类的内容吗?这是一个Active Directory环境,我们在IIS中使用WindowsAuthentication
。
这是我的SaveChanges代码:
public override int SaveChanges()
{
var changeSet = ChangeTracker.Entries<IAuditable>();
if (changeSet != null)
{
foreach (var entry in changeSet.Where(c => c.State != EntityState.Unchanged))
{
entry.Entity.ModifiedDate = DateProvider.GetCurrentDate();
}
}
return base.SaveChanges();
}
答案 0 :(得分:39)
您可以使用HttpContext.Current.User.Identity.Name
获取当前用户的名称。
public override int SaveChanges()
{
var changeSet = ChangeTracker.Entries<IAuditable>();
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();
}
更好的方法是使用构造函数注入将当前用户传递给上下文
public class MyContext : DbContext
{
public MyContext(string userName)
{
UserName = userName;
}
public string UserName
{
get; private set;
}
public override int SaveChanges()
{
var changeSet = ChangeTracker.Entries<IAuditable>();
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();
}
}
答案 1 :(得分:10)
我还想在我的MVC 4 / Entity Framework 5应用程序上自动化审计字段的数量。我使用来自@ Eranga的答案和本博客的信息:http://lourenco.co.za/blog/2013/07/audit-trails-concurrency-and-soft-deletion-with-entity-framework/使这个方法对我来说对Ninject起作用 - 发布以防其他任何人有价值:
创建了一个接口和抽象类:
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; }
}
在我的实体中使用它们:
public class DataEntity : AuditableEntity {
public int DataEntityID { get; set; }
...
}
为MyDbContext添加了一个构造函数,它接受了HttpContext并覆盖了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<IAuditableEntity>()) {
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();
}
最后 - 需要为每个请求提供一个DbContext并根据以下答案传递HttpContext:https://stackoverflow.com/a/3617961/1803682 - 请注意,由于MyDbContext
现在是请求范围,因此存储库必须也是如此。
kernel.Bind<IDataRepository>()
.To<EFDataRepository>()
.InRequestScope();
kernel.Bind<MyDbContext>().ToSelf()
.InRequestScope()
.WithConstructorArgument("context", ninjectContext=>HttpContext.Current);