如何在 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;
        }
    }
}