如何在 asp.net mvc 中创建审计日志/审计跟踪
How to create audit log / audit trail in asp.net mvc
当我们首先使用代码或 entity framework 时,有最简单的方法来审计跟踪添加、更新和删除等操作。
创建一个 class 以在添加、修改或删除实体时捕获更改或跟踪更改。
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations.Schema;
using System.Data.Entity;
using System.Data.Entity.Infrastructure;
using System.Linq;
using System.Text;
using System.Web;
namespace MVC_AuditTrail.Models
{
public class AuditTrailFactory
{
private DbContext context;
public AuditTrailFactory(DbContext context)
{
this.context = context;
}
public Audit GetAudit(DbEntityEntry entry)
{
Audit audit = new Audit();
// var user = (User)HttpContext.Current.Session[":user"];
audit.UserId = "swapnil";// user.UserName;
audit.TableName = GetTableName(entry);
audit.UpdateDate = DateTime.Now;
audit.TableIdValue = GetKeyValue(entry);
//entry is Added
if (entry.State == EntityState.Added)
{
var newValues = new StringBuilder();
SetAddedProperties(entry, newValues);
audit.NewData = newValues.ToString();
audit.Actions = AuditActions.I.ToString();
}
//entry in deleted
else if (entry.State == EntityState.Deleted)
{
var oldValues = new StringBuilder();
SetDeletedProperties(entry, oldValues);
audit.OldData = oldValues.ToString();
audit.Actions = AuditActions.D.ToString();
}
//entry is modified
else if (entry.State == EntityState.Modified)
{
var oldValues = new StringBuilder();
var newValues = new StringBuilder();
SetModifiedProperties(entry, oldValues, newValues);
audit.OldData = oldValues.ToString();
audit.NewData = newValues.ToString();
audit.Actions = AuditActions.U.ToString();
}
return audit;
}
private void SetAddedProperties(DbEntityEntry entry, StringBuilder newData)
{
foreach (var propertyName in entry.CurrentValues.PropertyNames)
{
var newVal = entry.CurrentValues[propertyName];
if (newVal != null)
{
newData.AppendFormat("{0}={1} || ", propertyName, newVal);
}
}
if (newData.Length > 0)
newData = newData.Remove(newData.Length - 3, 3);
}
private void SetDeletedProperties(DbEntityEntry entry, StringBuilder oldData)
{
DbPropertyValues dbValues = entry.GetDatabaseValues();
foreach (var propertyName in dbValues.PropertyNames)
{
var oldVal = dbValues[propertyName];
if (oldVal != null)
{
oldData.AppendFormat("{0}={1} || ", propertyName, oldVal);
}
}
if (oldData.Length > 0)
oldData = oldData.Remove(oldData.Length - 3, 3);
}
private void SetModifiedProperties(DbEntityEntry entry, StringBuilder oldData, StringBuilder newData)
{
DbPropertyValues dbValues = entry.GetDatabaseValues();
foreach (var propertyName in entry.OriginalValues.PropertyNames)
{
var oldVal = dbValues[propertyName];
var newVal = entry.CurrentValues[propertyName];
if (oldVal != null && newVal != null && !Equals(oldVal, newVal))
{
newData.AppendFormat("{0}={1} || ", propertyName, newVal);
oldData.AppendFormat("{0}={1} || ", propertyName, oldVal);
}
}
if (oldData.Length > 0)
oldData = oldData.Remove(oldData.Length - 3, 3);
if (newData.Length > 0)
newData = newData.Remove(newData.Length - 3, 3);
}
public long? GetKeyValue(DbEntityEntry entry)
{
var objectStateEntry = ((IObjectContextAdapter)context).ObjectContext.ObjectStateManager.GetObjectStateEntry(entry.Entity);
long id = 0;
if (objectStateEntry.EntityKey.EntityKeyValues != null)
id = Convert.ToInt64(objectStateEntry.EntityKey.EntityKeyValues[0].Value);
return id;
}
private string GetTableName(DbEntityEntry dbEntry)
{
TableAttribute tableAttr = dbEntry.Entity.GetType().GetCustomAttributes(typeof(TableAttribute), false).SingleOrDefault() as TableAttribute;
string tableName = tableAttr != null ? tableAttr.Name : dbEntry.Entity.GetType().Name;
return tableName;
}
}
public enum AuditActions
{
I,
U,
D
}
}
然后创建审计table实体和上下文class。
并在此方法中重写 savechanges 方法获取审核更改并在保存基本实体之前保存。
using System;
using System.Collections.Generic;
using System.Data.Entity;
using System.Data.Entity.Infrastructure;
using System.Linq;
using System.Web;
namespace MVC_AuditTrail.Models
{
public class Student
{
public int StudentID { get; set; }
public string Name { get; set; }
public string mobile { get; set; }
}
public class Audit
{
public long Id { get; set; }
public string TableName { get; set; }
public string UserId { get; set; }
public string Actions { get; set; }
public string OldData { get; set; }
public string NewData { get; set; }
public Nullable<long> TableIdValue { get; set; }
public Nullable<System.DateTime> UpdateDate { get; set; }
}
public class StdContext : DbContext
{
private AuditTrailFactory auditFactory;
private List<Audit> auditList = new List<Audit>();
private List<DbEntityEntry> objectList = new List<DbEntityEntry>();
public StdContext() : base("stdConnection")
{
Database.SetInitializer<StdContext>(new CreateDatabaseIfNotExists<StdContext>());
}
public DbSet<Student> Student { get; set; }
public DbSet<Audit> Audit { get; set; }
public override int SaveChanges()
{
auditList.Clear();
objectList.Clear();
auditFactory = new AuditTrailFactory(this);
var entityList = ChangeTracker.Entries().Where(p => p.State == EntityState.Added || p.State == EntityState.Deleted || p.State == EntityState.Modified);
foreach (var entity in entityList)
{
Audit audit = auditFactory.GetAudit(entity);
bool isValid = true;
if (entity.State == EntityState.Modified && string.IsNullOrWhiteSpace(audit.NewData) && string.IsNullOrWhiteSpace(audit.OldData))
{
isValid = false;
}
if (isValid)
{
auditList.Add(audit);
objectList.Add(entity);
}
}
var retVal = base.SaveChanges();
if (auditList.Count > 0)
{
int i = 0;
foreach (var audit in auditList)
{
if (audit.Actions == AuditActions.I.ToString())
audit.TableIdValue = auditFactory.GetKeyValue(objectList[i]);
this.Audit.Add(audit);
i++;
}
base.SaveChanges();
}
return retVal;
}
}
}
当我们首先使用代码或 entity framework 时,有最简单的方法来审计跟踪添加、更新和删除等操作。
创建一个 class 以在添加、修改或删除实体时捕获更改或跟踪更改。
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations.Schema;
using System.Data.Entity;
using System.Data.Entity.Infrastructure;
using System.Linq;
using System.Text;
using System.Web;
namespace MVC_AuditTrail.Models
{
public class AuditTrailFactory
{
private DbContext context;
public AuditTrailFactory(DbContext context)
{
this.context = context;
}
public Audit GetAudit(DbEntityEntry entry)
{
Audit audit = new Audit();
// var user = (User)HttpContext.Current.Session[":user"];
audit.UserId = "swapnil";// user.UserName;
audit.TableName = GetTableName(entry);
audit.UpdateDate = DateTime.Now;
audit.TableIdValue = GetKeyValue(entry);
//entry is Added
if (entry.State == EntityState.Added)
{
var newValues = new StringBuilder();
SetAddedProperties(entry, newValues);
audit.NewData = newValues.ToString();
audit.Actions = AuditActions.I.ToString();
}
//entry in deleted
else if (entry.State == EntityState.Deleted)
{
var oldValues = new StringBuilder();
SetDeletedProperties(entry, oldValues);
audit.OldData = oldValues.ToString();
audit.Actions = AuditActions.D.ToString();
}
//entry is modified
else if (entry.State == EntityState.Modified)
{
var oldValues = new StringBuilder();
var newValues = new StringBuilder();
SetModifiedProperties(entry, oldValues, newValues);
audit.OldData = oldValues.ToString();
audit.NewData = newValues.ToString();
audit.Actions = AuditActions.U.ToString();
}
return audit;
}
private void SetAddedProperties(DbEntityEntry entry, StringBuilder newData)
{
foreach (var propertyName in entry.CurrentValues.PropertyNames)
{
var newVal = entry.CurrentValues[propertyName];
if (newVal != null)
{
newData.AppendFormat("{0}={1} || ", propertyName, newVal);
}
}
if (newData.Length > 0)
newData = newData.Remove(newData.Length - 3, 3);
}
private void SetDeletedProperties(DbEntityEntry entry, StringBuilder oldData)
{
DbPropertyValues dbValues = entry.GetDatabaseValues();
foreach (var propertyName in dbValues.PropertyNames)
{
var oldVal = dbValues[propertyName];
if (oldVal != null)
{
oldData.AppendFormat("{0}={1} || ", propertyName, oldVal);
}
}
if (oldData.Length > 0)
oldData = oldData.Remove(oldData.Length - 3, 3);
}
private void SetModifiedProperties(DbEntityEntry entry, StringBuilder oldData, StringBuilder newData)
{
DbPropertyValues dbValues = entry.GetDatabaseValues();
foreach (var propertyName in entry.OriginalValues.PropertyNames)
{
var oldVal = dbValues[propertyName];
var newVal = entry.CurrentValues[propertyName];
if (oldVal != null && newVal != null && !Equals(oldVal, newVal))
{
newData.AppendFormat("{0}={1} || ", propertyName, newVal);
oldData.AppendFormat("{0}={1} || ", propertyName, oldVal);
}
}
if (oldData.Length > 0)
oldData = oldData.Remove(oldData.Length - 3, 3);
if (newData.Length > 0)
newData = newData.Remove(newData.Length - 3, 3);
}
public long? GetKeyValue(DbEntityEntry entry)
{
var objectStateEntry = ((IObjectContextAdapter)context).ObjectContext.ObjectStateManager.GetObjectStateEntry(entry.Entity);
long id = 0;
if (objectStateEntry.EntityKey.EntityKeyValues != null)
id = Convert.ToInt64(objectStateEntry.EntityKey.EntityKeyValues[0].Value);
return id;
}
private string GetTableName(DbEntityEntry dbEntry)
{
TableAttribute tableAttr = dbEntry.Entity.GetType().GetCustomAttributes(typeof(TableAttribute), false).SingleOrDefault() as TableAttribute;
string tableName = tableAttr != null ? tableAttr.Name : dbEntry.Entity.GetType().Name;
return tableName;
}
}
public enum AuditActions
{
I,
U,
D
}
}
然后创建审计table实体和上下文class。
并在此方法中重写 savechanges 方法获取审核更改并在保存基本实体之前保存。
using System;
using System.Collections.Generic;
using System.Data.Entity;
using System.Data.Entity.Infrastructure;
using System.Linq;
using System.Web;
namespace MVC_AuditTrail.Models
{
public class Student
{
public int StudentID { get; set; }
public string Name { get; set; }
public string mobile { get; set; }
}
public class Audit
{
public long Id { get; set; }
public string TableName { get; set; }
public string UserId { get; set; }
public string Actions { get; set; }
public string OldData { get; set; }
public string NewData { get; set; }
public Nullable<long> TableIdValue { get; set; }
public Nullable<System.DateTime> UpdateDate { get; set; }
}
public class StdContext : DbContext
{
private AuditTrailFactory auditFactory;
private List<Audit> auditList = new List<Audit>();
private List<DbEntityEntry> objectList = new List<DbEntityEntry>();
public StdContext() : base("stdConnection")
{
Database.SetInitializer<StdContext>(new CreateDatabaseIfNotExists<StdContext>());
}
public DbSet<Student> Student { get; set; }
public DbSet<Audit> Audit { get; set; }
public override int SaveChanges()
{
auditList.Clear();
objectList.Clear();
auditFactory = new AuditTrailFactory(this);
var entityList = ChangeTracker.Entries().Where(p => p.State == EntityState.Added || p.State == EntityState.Deleted || p.State == EntityState.Modified);
foreach (var entity in entityList)
{
Audit audit = auditFactory.GetAudit(entity);
bool isValid = true;
if (entity.State == EntityState.Modified && string.IsNullOrWhiteSpace(audit.NewData) && string.IsNullOrWhiteSpace(audit.OldData))
{
isValid = false;
}
if (isValid)
{
auditList.Add(audit);
objectList.Add(entity);
}
}
var retVal = base.SaveChanges();
if (auditList.Count > 0)
{
int i = 0;
foreach (var audit in auditList)
{
if (audit.Actions == AuditActions.I.ToString())
audit.TableIdValue = auditFactory.GetKeyValue(objectList[i]);
this.Audit.Add(audit);
i++;
}
base.SaveChanges();
}
return retVal;
}
}
}