public abstract class AuditableService
{
protected readonly IAuditService _audit;
protected readonly ICurrentUserService _currentUser;
protected readonly ILogger _logger;
protected AuditableService(
IAuditService audit,
ICurrentUserService currentUser,
ILogger logger)
{
_audit = audit;
_currentUser = currentUser;
_logger = logger;
}
protected async Task ExecuteWithAuditAsync(
Func<Task> action,
AuditAction auditAction,
string description)
{
_logger.LogInformation("Action started: {Action}", auditAction);
await action();
await _audit.LogAsync(
_currentUser.GetCurrentUserId(),
_currentUser.GetCompanyId(),
auditAction,
description
);
_logger.LogInformation("Action finished: {Action}", auditAction);
}
}
//This is the implementation of the Base class
It injects its self -needed plus services the base class woulld also need and passes it to the base class with :base(audit, currentUser,logger)
With this,every derived class have a unified Audit and Loge service plus their cutom implemetation..
public class WarehouseService
: AuditableService, IWarehouseService
{
private readonly IAppDbContext _context;
public WarehouseService(
IAppDbContext context,
IAuditService audit,
ICurrentUserService currentUser,
ILogger<WarehouseService> logger)
: base(audit, currentUser, logger)
{
_context = context;
}
public async Task CreateWarehouseAsync(string name)
{
await ExecuteWithAuditAsync(
async () =>
{
var warehouse = new Warehouse
{
Name = name,
CompanyId = _currentUser.GetCompanyId()
};
_context.Warehouses.Add(warehouse);
await _context.SaveChangesAsync();
},
AuditAction.CreateWarehouse,
$"Warehouse '{name}' created"
);
}
public async Task DeleteWarehouseAsync(Guid warehouseId)
{
await ExecuteWithAuditAsync(
async () =>
{
var warehouse = await _context.Warehouses.FindAsync(warehouseId);
warehouse.MarkAsDeleted();
await _context.SaveChangesAsync();
},
AuditAction.DeleteWarehouse,
$"Warehouse {warehouseId} deleted"
);
}
}