如何在 asp.net mvc 中创建审计日志/审计跟踪

Posted

技术标签:

【中文标题】如何在 asp.net mvc 中创建审计日志/审计跟踪【英文标题】:How to create audit log / audit trail in asp.net mvc 【发布时间】:2016-09-15 08:55:30 【问题描述】:

当我们首先使用代码或实体框架时,有最简单的方法来审计跟踪添加、更新和删除等操作。

【问题讨论】:

查看Audit.EntityFramework 库,为 EntityFramework 的 CRUD 操作生成审计跟踪。 【参考方案1】:

创建一个类以在实体添加、修改或删除时捕获更改或跟踪更改。

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


然后创建审计表实体和上下文类。

并在此方法中覆盖 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;
        
    

【讨论】:

以上是关于如何在 asp.net mvc 中创建审计日志/审计跟踪的主要内容,如果未能解决你的问题,请参考以下文章

如何在 C# Asp.net MVC 中创建 websocket 客户端?

我们如何使用 EF 在 ASP.Net MVC 应用程序中创建 3 层架构?

如何在 Visual Studio 2017 的 ASP.NET MVC 中创建自定义生成/脚手架模板(Razor)?

如何在 ASP .net MVC 4 应用程序的 HTML5 中创建带有可点击选项的水平条形图? [关闭]

如何在现有数据库中创建 ASP.Net Identity 表?

在 ASP.NET MVC 3 中创建基于平台显示不同视图的自定义 ViewResult