161 lines
5.2 KiB
C#
161 lines
5.2 KiB
C#
using System;
|
|
using System.Linq;
|
|
using System.Threading;
|
|
using System.Threading.Tasks;
|
|
using IRaCIS.Core.Domain.Models;
|
|
using IRaCIS.Core.Infra.EFCore;
|
|
using Microsoft.EntityFrameworkCore;
|
|
using Microsoft.EntityFrameworkCore.ChangeTracking;
|
|
using Microsoft.EntityFrameworkCore.Diagnostics;
|
|
|
|
public class AuditingInterceptor : ISaveChangesInterceptor
|
|
{
|
|
private readonly string _connectionString;
|
|
private SaveChangesAudit _audit;
|
|
|
|
public AuditingInterceptor(string connectionString)
|
|
{
|
|
_connectionString = connectionString;
|
|
}
|
|
|
|
#region SavingChanges
|
|
public async ValueTask<InterceptionResult<int>> SavingChangesAsync(
|
|
DbContextEventData eventData,
|
|
InterceptionResult<int> result,
|
|
CancellationToken cancellationToken = default)
|
|
{
|
|
_audit = CreateAudit(eventData.Context);
|
|
|
|
await Task.CompletedTask;
|
|
return result;
|
|
|
|
|
|
}
|
|
|
|
public InterceptionResult<int> SavingChanges(
|
|
DbContextEventData eventData,
|
|
InterceptionResult<int> result)
|
|
{
|
|
_audit = CreateAudit(eventData.Context);
|
|
|
|
return result;
|
|
}
|
|
#endregion
|
|
|
|
#region SavedChanges
|
|
public int SavedChanges(SaveChangesCompletedEventData eventData, int result)
|
|
{
|
|
if (_audit.Entities.Count > 0)
|
|
{
|
|
var auditContext = eventData.Context as IRaCISDBContext;
|
|
_audit.Succeeded = true;
|
|
_audit.EndTime = DateTime.Now;
|
|
auditContext.SaveChangesAudits.Add(_audit);
|
|
auditContext.SaveChanges();
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
public async ValueTask<int> SavedChangesAsync(
|
|
SaveChangesCompletedEventData eventData,
|
|
int result,
|
|
CancellationToken cancellationToken = default)
|
|
{
|
|
if (_audit.Entities.Count > 0)
|
|
{
|
|
var auditContext = eventData.Context as IRaCISDBContext;
|
|
_audit.Succeeded = true;
|
|
auditContext.SaveChangesAudits.Add(_audit);
|
|
_audit.EndTime = DateTime.Now;
|
|
|
|
await auditContext.SaveChangesAsync();
|
|
}
|
|
|
|
return result;
|
|
}
|
|
#endregion
|
|
|
|
#region SaveChangesFailed
|
|
public void SaveChangesFailed(DbContextErrorEventData eventData)
|
|
{
|
|
using (var auditContext = new AuditContext(_connectionString))
|
|
{
|
|
auditContext.Attach(_audit);
|
|
_audit.Succeeded = false;
|
|
_audit.EndTime = DateTime.Now;
|
|
_audit.ErrorMessage = eventData.Exception.Message;
|
|
|
|
auditContext.SaveChanges();
|
|
}
|
|
}
|
|
|
|
public async Task SaveChangesFailedAsync(
|
|
DbContextErrorEventData eventData,
|
|
CancellationToken cancellationToken = default)
|
|
{
|
|
using (var auditContext = new AuditContext(_connectionString))
|
|
{
|
|
auditContext.Attach(_audit);
|
|
_audit.Succeeded = false;
|
|
_audit.EndTime = DateTime.Now;
|
|
_audit.ErrorMessage = eventData.Exception.InnerException?.Message;
|
|
|
|
await auditContext.SaveChangesAsync(cancellationToken);
|
|
}
|
|
}
|
|
#endregion
|
|
|
|
|
|
|
|
#region CreateAudit
|
|
private static bool NeedAudit(EntityEntry entityEntry)
|
|
{
|
|
var type = entityEntry.Entity.GetType();
|
|
return type != typeof(EntityAudit) && type != typeof(SaveChangesAudit) && type != typeof(DicomSeries) && type != typeof(DicomInstance) && type != typeof(TrialAudit);
|
|
}
|
|
|
|
private static SaveChangesAudit CreateAudit(DbContext context)
|
|
{
|
|
context.ChangeTracker.DetectChanges();
|
|
|
|
var audit = new SaveChangesAudit { StartTime = DateTime.Now };
|
|
|
|
foreach (var entry in context.ChangeTracker.Entries().Where(t => NeedAudit(t)))
|
|
{
|
|
var auditMessage = entry.State switch
|
|
{
|
|
EntityState.Deleted => CreateDeletedMessage(entry),
|
|
EntityState.Modified => CreateModifiedMessage(entry),
|
|
EntityState.Added => CreateAddedMessage(entry),
|
|
_ => null
|
|
};
|
|
|
|
if (auditMessage != null)
|
|
{
|
|
var alterIdStr = entry.CurrentValues["Id"].ToString();
|
|
audit.Entities.Add(new EntityAudit { State = entry.State, AuditMessage = auditMessage, AlterId = Guid.Parse(alterIdStr) });
|
|
}
|
|
}
|
|
|
|
return audit;
|
|
|
|
string CreateAddedMessage(EntityEntry entry)
|
|
=>
|
|
entry.Properties.Aggregate(
|
|
$"Inserting {entry.Metadata.DisplayName()} with ",
|
|
(auditString, property) => auditString + $"{property.Metadata.Name}: '{property.CurrentValue}' ");
|
|
|
|
string CreateModifiedMessage(EntityEntry entry)
|
|
=> entry.Properties.Where(property => property.IsModified || property.Metadata.IsPrimaryKey()).Aggregate(
|
|
$"Updating {entry.Metadata.DisplayName()} with ",
|
|
(auditString, property) => auditString + $"{property.Metadata.Name}: '{property.CurrentValue}' ");
|
|
|
|
string CreateDeletedMessage(EntityEntry entry)
|
|
=> entry.Properties.Where(property => property.Metadata.IsPrimaryKey()).Aggregate(
|
|
$"Deleting {entry.Metadata.DisplayName()} with ",
|
|
(auditString, property) => auditString + $"{property.Metadata.Name}: '{property.CurrentValue}' ");
|
|
}
|
|
#endregion
|
|
|
|
} |