Audit Trail Component + Full Source Code
Version v1.0
Introduction
Audit trail component stores database actions (Add, Update, Delete), business actions (you can specify them), sends notifications and logs its own errors, also it’s dynamic as it gives user the ability to specify [Business actions], [Emails that notifications will be sent to], [Notification’s subject] and [Notification’s Message], also you can search for all the data has been stored by the component by predefined methods.
Framework: .net standard 2.1
Packages :
Hangfire Packages :
Features :
Recommendation :
use background job to execute component methods, to ensure that the original request time will not be increased.
Database Tables
Audit.Action
to store actions lookup data
Audit.ActionUserGroup
to make relation between [action], and emails, so if this action happened then the component will send notification to the related emails with the specified message.
Audit.AuditTrail
to store the audit data
Audit.ErrorLog
to log the component errors
Audit.Notification
to store the notifications that the component will send to emails
Audit.NotificationLog
to log the send notification process, component will store every (send email) retry and store if it’s done successfully or not with error message
How to Register
Startup class
#region hangfire
// Add Hangfire services.
services.AddHangfire(configuration => configuration
.SetDataCompatibilityLevel(CompatibilityLevel.Version_170)
.UseSimpleAssemblyNameTypeSerializer()
.UseRecommendedSerializerSettings()
.UseSqlServerStorage(Configuration.GetConnectionString(“DefaultConnection”), new SqlServerStorageOptions
{
CommandBatchMaxTimeout = TimeSpan.FromMinutes(5),
SlidingInvisibilityTimeout = TimeSpan.FromMinutes(5),
QueuePollInterval = TimeSpan.Zero,
UseRecommendedIsolationLevel = true,
UsePageLocksOnDequeue = true,
DisableGlobalLocks = true
}));
// Add the processing server as IHostedService
services.AddHangfireServer();
#endregion
#region Audit
services.AddScoped<IEmailService, EmailService>();
//AddAuditTrail classes
services.AddAuditTrail(Configuration.GetConnectionString(“DefaultConnection”),
new List<AuditActionDto> {
new AuditActionDto() { ActionCode =”CreateOrder”,SendNotification=true,NotificationFromEmail=” [email protected] “
,NotificationEmails=”[email protected], [email protected] ”,NotificationSubject=”subject “
,NotificationMessage=”sample message”},
new AuditActionDto() { ActionCode = “DeleteOrder”,SendNotification=true,NotificationFromEmail=”[email protected]”,
NotificationEmails=”[email protected], [email protected] ”,NotificationSubject=”subject “ ,
NotificationMessage=”sample message2” },
new AuditActionDto() { ActionCode = “UpdateOrder” ,SendNotification=true},
new AuditActionDto() { ActionCode = “NewUpdateOrder” ,SendNotification=false}});
//register background job to Check Notifications to send emails
var sp = services.BuildServiceProvider().CreateScope().ServiceProvider;
var notificationService = sp.GetService<INotificationPublicService>();
JobStorage.Current = new SqlServerStorage(Configuration.GetConnectionString(“DefaultConnection”),
new SqlServerStorageOptions
{
CommandBatchMaxTimeout = TimeSpan.FromMinutes(5),
SlidingInvisibilityTimeout = TimeSpan.FromMinutes(5),
QueuePollInterval = TimeSpan.Zero,
UseRecommendedIsolationLevel = true,
UsePageLocksOnDequeue = true,
DisableGlobalLocks = true
});
RecurringJob.AddOrUpdate(() => notificationService.CheckNotificationsAndSend(), Cron.Daily);
#endregion
How to create tables
How to use
BackgroundJob.Enqueue(() => AuditTrailService.SaveCustomActionsAuditTrailAsync(“DeleteOrder”, “sample data by hangfire”, “username1”));
BackgroundJob.Enqueue(() =>AuditTrailService.SaveDbActionsAuditTrailAsync(ApplicationDbContext.ChangeTracker.Entries()
.Select(a =>
new DatabaseChangesDto
{
Entity = a.Entity,
OriginalValues = a.OriginalValues.ToObject(),
CurrentValues = a.CurrentValues.ToObject()
}).ToList()));
//Inject this interface [IAuditTrailService]
AuditTrailFilterDto model = new AuditTrailFilterDto {Audit_ActionCode=”DeleteOrder” };
var result=await AuditTrailService.Search(model);
//Inject this interface [INotificationPublicService]
NotificationFilterDto model = new NotificationFilterDto { Audit_ActionCode=”DeleteOrder” };
var result=await NotificationPublicService.SearchNotifications(model);
//Inject this interface [IErrorLogPublicService]
NotificationLogFilterDto model = new NotificationLogFilterDto { };
var result = await NotificationService.SearchNotificationLogs(model);
//Inject this interface [IErrorLogPublicService]
ErrorLogFilterDto model4 = new ErrorLogFilterDto();
var result = await ErrorLogPublicService.Search(model4);