如何使用 Audit.net 将 Update<T>(IList<T>) 操作记录为多个审计记录
How to log Update<T>(IList<T>) action as multiple audit records using Audit.net
我必须更新 table 中的批量记录。我是这样做的。
BaseRepository.cs
public IList<T> Update<T>(IList<T> instance) where T : class
{
IList<T> insertedItems = new List<T>();
int totalCount = instance.Count;
int count = 0;
foreach (var item in instance)
{
insertedItems.Add(Update(item, count == (totalCount - 1)));
count++;
}
try
{
context.SaveChanges();
}
catch (DbEntityValidationException ex)
{
//HandleDbEntityValidationException(ex);
}
//
return insertedItems;
}
测试方法
public bool TestUpdate()
{
try
{
List<Test> list = new List<Test>();
Test test1 = new Test();
test1.Id = 3;
test1.Message = "test string updated 40";
Test test2 = new Test();
test2.Id = 4;
list.Add(test1); list.Add(test2);
test2.Message = "test string updated 7";
_repository.Update<Test>(list);
this.unitOfWork.Save();
}
catch (Exception ex)
{
}
finally
{
this.unitOfWork.Dispose();
}
return true;
}
然后想用Audit.net做日志审计。我做了如下...
Global.asax.cs
Audit.Core.Configuration.DataProvider = new SqlDataProvider()
{
ConnectionString = "Data Source=FTD-NB-MADHARA;Initial Catalog=TestAuditTrail;User ID=sctavp_user;Password=welcome@123;MultipleActiveResultSets=true",
Schema = "dbo",
TableName = "Event",
IdColumnName = "EventId",
JsonColumnName = "JsonData",
CustomColumns = new List<CustomColumn>()
{
new CustomColumn("UserName", ev=> ev.Environment.UserName.ToString()),
new CustomColumn("MachineName", ev=> ev.Environment.MachineName.ToString()),
new CustomColumn("DomainName", ev=> ev.Environment.DomainName.ToString()),
new CustomColumn("ModuleName", ev => "AuditTrail"),
new CustomColumn("CallingMethod", ev=> ev.Environment.CallingMethodName.ToString()),
new CustomColumn("DatabaseName", ev=> ev.GetEntityFrameworkEvent().Database.ToString()),
new CustomColumn("SchemaName", ev=> ev.GetEntityFrameworkEvent().Entries[0].Schema.ToString()),
new CustomColumn("TableName", ev=> ev.GetEntityFrameworkEvent().Entries[0].Table.ToString()),
new CustomColumn("Action", ev=> ev.GetEntityFrameworkEvent().Entries[0].Action.ToString()),}};
上下文变化
private static DbContextHelper _helper = new DbContextHelper();
private readonly IAuditDbContext _auditContext;
public AuditTrailContext() : base("ApplicationDatabase")
{
//AuditDataProvider = new NullDataProvider();
_auditContext = new DefaultAuditContext(this);
_helper.SetConfig(_auditContext);
}
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Conventions.Add(new DecimalPrecisionAttributeConvention());
}
#region without AuditDbContext
public override int SaveChanges()
{
return _helper.SaveChanges(_auditContext, () => base.SaveChanges());
}
public override async Task<int> SaveChangesAsync(CancellationToken cancellationToken = default(CancellationToken))
{
return await _helper.SaveChangesAsync(_auditContext, () => base.SaveChangesAsync(cancellationToken));
}
结果
JsonData 字段
{"EventType":"DefaultAuditContext","Environment":{"UserName":"MadharaU","MachineName":"FTD-NB-MADHARA","DomainName":"BRANDIXLK","CallingMethodName":"Rocky.AuditService.Data.EntityManager.BaseRepository.Update()","AssemblyName":"Rocky.AuditService.Data.EntityManager, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null","Culture":"en-US"},"StartDate":"2021-02-23T03:52:47.0005326Z","EndDate":"2021-02-23T03:52:47.0371697Z","Duration":37,"EntityFrameworkEvent":{"Database":"AuditTrail","Entries":[{"Schema":"dbo","Table":"Test","Action":"Update","PrimaryKey":{"Id":3},"Changes":[{"ColumnName":"Message","OriginalValue":"test string updated 39","NewValue":"test string updated 40"}],"ColumnValues":{"Id":3,"Message":"test string updated 40"},"Valid":true,"ValidationResults":[]},{"Schema":"dbo","Table":"Test","Action":"Update","PrimaryKey":{"Id":4},"Changes":[{"ColumnName":"Message","OriginalValue":"test string updated 6","NewValue":"test string updated 7"}],"ColumnValues":{"Id":4,"Message":"test string updated 7"},"Valid":true,"ValidationResults":[]}],"Result":2,"Success":true}}
现在我的问题是,我同时更新了两条记录。 Audit.NET 在审计 table 中将两者记录为一条记录。有什么方法可以分别为这两个更新插入日志详细信息。
您至少有两个选择
使用 Entity Framework 数据提供程序
如果您可以将审核日志 table 映射到 Entity Framework DbContext(它可以是您正在审核的相同 DbContext 或不同的 DbContext),那么您可以使用 EntityFramework Data Provider 而不是 SQL 数据提供程序。
例如,假设您有一个 AuditLog table 映射到 DbContext:
public class AuditLog
{
public int Id { get; set; }
public DateTime Date { get; set; }
public string User { get; set; }
public string Table { get; set; }
public string JsonData { get; set; }
}
public class LogsDbContext : DbContext
{
public DbSet<AuditLog> AuditLogs { get; set; }
//...
}
然后您可以设置 EF 数据提供程序以将每个已审核的条目记录到 AuditLog 上的记录中 table:
Audit.Core.Configuration.Setup()
.UseEntityFramework(config => config
.UseDbContext<LogsDbContext>()
.AuditTypeMapper(_ => typeof(AuditLog))
.AuditEntityAction<AuditLog>((ev, entry, auditLog) =>
{
auditLog.Date = DateTime.UtcNow;
auditLog.Table = entry.Table;
auditLog.User = ev.Environment.UserName;
auditLog.JsonData = entry.ToJson();
})
.IgnoreMatchedProperties(true));
使用自定义 SQL 数据提供程序
继承自SqlDataProvider,重写Insert/InsertAsync触发每个实体条目的保存:
public class SingleSqlProvider : SqlDataProvider
{
public SingleSqlProvider(Action<ISqlServerProviderConfigurator> config) : base(config) { }
public override object InsertEvent(AuditEvent auditEvent)
{
var efEvent = auditEvent as AuditEventEntityFramework;
object lastId = null;
if (efEvent != null)
{
foreach (var entry in efEvent.EntityFrameworkEvent.Entries)
{
var clone = AuditEvent.FromJson<AuditEventEntityFramework>(auditEvent.ToJson());
clone.EntityFrameworkEvent.Entries.Clear();
clone.EntityFrameworkEvent.Entries.Add(entry);
lastId = base.InsertEvent(clone);
}
}
else
{
return base.InsertEvent(auditEvent);
}
return lastId;
}
public async override Task<object> InsertEventAsync(AuditEvent auditEvent)
{
// same but Async...
}
}
那么设置可以是:
Audit.Core.Configuration.Setup()
.UseCustomProvider(new SingleSqlProvider(config => config
.ConnectionString("...")
.TableName("...")));
我必须更新 table 中的批量记录。我是这样做的。
BaseRepository.cs
public IList<T> Update<T>(IList<T> instance) where T : class
{
IList<T> insertedItems = new List<T>();
int totalCount = instance.Count;
int count = 0;
foreach (var item in instance)
{
insertedItems.Add(Update(item, count == (totalCount - 1)));
count++;
}
try
{
context.SaveChanges();
}
catch (DbEntityValidationException ex)
{
//HandleDbEntityValidationException(ex);
}
//
return insertedItems;
}
测试方法
public bool TestUpdate()
{
try
{
List<Test> list = new List<Test>();
Test test1 = new Test();
test1.Id = 3;
test1.Message = "test string updated 40";
Test test2 = new Test();
test2.Id = 4;
list.Add(test1); list.Add(test2);
test2.Message = "test string updated 7";
_repository.Update<Test>(list);
this.unitOfWork.Save();
}
catch (Exception ex)
{
}
finally
{
this.unitOfWork.Dispose();
}
return true;
}
然后想用Audit.net做日志审计。我做了如下...
Global.asax.cs
Audit.Core.Configuration.DataProvider = new SqlDataProvider()
{
ConnectionString = "Data Source=FTD-NB-MADHARA;Initial Catalog=TestAuditTrail;User ID=sctavp_user;Password=welcome@123;MultipleActiveResultSets=true",
Schema = "dbo",
TableName = "Event",
IdColumnName = "EventId",
JsonColumnName = "JsonData",
CustomColumns = new List<CustomColumn>()
{
new CustomColumn("UserName", ev=> ev.Environment.UserName.ToString()),
new CustomColumn("MachineName", ev=> ev.Environment.MachineName.ToString()),
new CustomColumn("DomainName", ev=> ev.Environment.DomainName.ToString()),
new CustomColumn("ModuleName", ev => "AuditTrail"),
new CustomColumn("CallingMethod", ev=> ev.Environment.CallingMethodName.ToString()),
new CustomColumn("DatabaseName", ev=> ev.GetEntityFrameworkEvent().Database.ToString()),
new CustomColumn("SchemaName", ev=> ev.GetEntityFrameworkEvent().Entries[0].Schema.ToString()),
new CustomColumn("TableName", ev=> ev.GetEntityFrameworkEvent().Entries[0].Table.ToString()),
new CustomColumn("Action", ev=> ev.GetEntityFrameworkEvent().Entries[0].Action.ToString()),}};
上下文变化
private static DbContextHelper _helper = new DbContextHelper();
private readonly IAuditDbContext _auditContext;
public AuditTrailContext() : base("ApplicationDatabase")
{
//AuditDataProvider = new NullDataProvider();
_auditContext = new DefaultAuditContext(this);
_helper.SetConfig(_auditContext);
}
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Conventions.Add(new DecimalPrecisionAttributeConvention());
}
#region without AuditDbContext
public override int SaveChanges()
{
return _helper.SaveChanges(_auditContext, () => base.SaveChanges());
}
public override async Task<int> SaveChangesAsync(CancellationToken cancellationToken = default(CancellationToken))
{
return await _helper.SaveChangesAsync(_auditContext, () => base.SaveChangesAsync(cancellationToken));
}
结果
JsonData 字段
{"EventType":"DefaultAuditContext","Environment":{"UserName":"MadharaU","MachineName":"FTD-NB-MADHARA","DomainName":"BRANDIXLK","CallingMethodName":"Rocky.AuditService.Data.EntityManager.BaseRepository.Update()","AssemblyName":"Rocky.AuditService.Data.EntityManager, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null","Culture":"en-US"},"StartDate":"2021-02-23T03:52:47.0005326Z","EndDate":"2021-02-23T03:52:47.0371697Z","Duration":37,"EntityFrameworkEvent":{"Database":"AuditTrail","Entries":[{"Schema":"dbo","Table":"Test","Action":"Update","PrimaryKey":{"Id":3},"Changes":[{"ColumnName":"Message","OriginalValue":"test string updated 39","NewValue":"test string updated 40"}],"ColumnValues":{"Id":3,"Message":"test string updated 40"},"Valid":true,"ValidationResults":[]},{"Schema":"dbo","Table":"Test","Action":"Update","PrimaryKey":{"Id":4},"Changes":[{"ColumnName":"Message","OriginalValue":"test string updated 6","NewValue":"test string updated 7"}],"ColumnValues":{"Id":4,"Message":"test string updated 7"},"Valid":true,"ValidationResults":[]}],"Result":2,"Success":true}}
现在我的问题是,我同时更新了两条记录。 Audit.NET 在审计 table 中将两者记录为一条记录。有什么方法可以分别为这两个更新插入日志详细信息。
您至少有两个选择
使用 Entity Framework 数据提供程序
如果您可以将审核日志 table 映射到 Entity Framework DbContext(它可以是您正在审核的相同 DbContext 或不同的 DbContext),那么您可以使用 EntityFramework Data Provider 而不是 SQL 数据提供程序。
例如,假设您有一个 AuditLog table 映射到 DbContext:
public class AuditLog
{
public int Id { get; set; }
public DateTime Date { get; set; }
public string User { get; set; }
public string Table { get; set; }
public string JsonData { get; set; }
}
public class LogsDbContext : DbContext
{
public DbSet<AuditLog> AuditLogs { get; set; }
//...
}
然后您可以设置 EF 数据提供程序以将每个已审核的条目记录到 AuditLog 上的记录中 table:
Audit.Core.Configuration.Setup()
.UseEntityFramework(config => config
.UseDbContext<LogsDbContext>()
.AuditTypeMapper(_ => typeof(AuditLog))
.AuditEntityAction<AuditLog>((ev, entry, auditLog) =>
{
auditLog.Date = DateTime.UtcNow;
auditLog.Table = entry.Table;
auditLog.User = ev.Environment.UserName;
auditLog.JsonData = entry.ToJson();
})
.IgnoreMatchedProperties(true));
使用自定义 SQL 数据提供程序
继承自SqlDataProvider,重写Insert/InsertAsync触发每个实体条目的保存:
public class SingleSqlProvider : SqlDataProvider
{
public SingleSqlProvider(Action<ISqlServerProviderConfigurator> config) : base(config) { }
public override object InsertEvent(AuditEvent auditEvent)
{
var efEvent = auditEvent as AuditEventEntityFramework;
object lastId = null;
if (efEvent != null)
{
foreach (var entry in efEvent.EntityFrameworkEvent.Entries)
{
var clone = AuditEvent.FromJson<AuditEventEntityFramework>(auditEvent.ToJson());
clone.EntityFrameworkEvent.Entries.Clear();
clone.EntityFrameworkEvent.Entries.Add(entry);
lastId = base.InsertEvent(clone);
}
}
else
{
return base.InsertEvent(auditEvent);
}
return lastId;
}
public async override Task<object> InsertEventAsync(AuditEvent auditEvent)
{
// same but Async...
}
}
那么设置可以是:
Audit.Core.Configuration.Setup()
.UseCustomProvider(new SingleSqlProvider(config => config
.ConnectionString("...")
.TableName("...")));