Chciałbym dodawać dane audytowe podczas modyfikacji i zapisu z poziomiu DbContextu.
Idzie to w ogóle zrobić przy "poolowaniu" kontekstów ?
Jakieś podpowiedzi jak to zrobić?
Hmm ciekawe. Może wykorzystać by wzorzec decorator?
@szydlak: Tylko jak to później zarejestrować ?
Nie wiem czy dobrze rozumiem. Ja to mam tak w jednym z projektów:
Startup.cs
services.AddTransient<IHttpContextAccessor, HttpContextAccessor>();
services.AddTransient<UserResolverService>();
UserResolverService.cs
public class UserResolverService
{
private readonly IHttpContextAccessor _context;
public UserResolverService(IHttpContextAccessor context)
{
_context = context;
}
public int GetUserId()
{
// Ja wrzucałem dane user do Claims'ów
ClaimsPrincipal cp = _context.HttpContext.User;
ClaimsIdentity ci = cp.Identities.FirstOrDefault();
string userJson = ci.Claims.FirstOrDefault(x => x.Type == "user").Value;
if(!string.IsNullOrEmpty(userJson))
{
AppUser user = JsonConvert.DeserializeObject<AppUser>(userJson);
return user.Id;
}
return 0;
}
}
KasiarzContext.cs
public class KasiarzContext : DbContext
{
private readonly UserResolverService _userResolver;
public KasiarzContext(DbContextOptions<KasiarzContext> options, UserResolverService userResolver)
: base(options)
{
_userResolver = userResolver;
}
public override int SaveChanges()
{
OnBeforeSaving();
return base.SaveChanges();
}
public override Task<int> SaveChangesAsync(CancellationToken cancellationToken = default(CancellationToken))
{
OnBeforeSaving();
return base.SaveChangesAsync();
}
private void OnBeforeSaving()
{
var entries = ChangeTracker.Entries();
foreach(var entry in entries)
{
if(entry.Entity is IDbTracking tracking)
{
var now = DateTime.Now;
//var user = 0;
var user = _userResolver.GetUserId();
switch (entry.State)
{
case EntityState.Modified:
tracking.ModifiedAt = now;
tracking.ModifiedBy = user;
break;
case EntityState.Added:
tracking.CreatedAt = now;
tracking.CreatedBy = user;
tracking.ModifiedAt = now;
tracking.ModifiedBy = user;
break;
default:
break;
}
}
}
}
}
To jest stary projekt. Tam są dopisywane tylko rzeczy jak trzeba. Nigdy nie było to "dopracowywane" do .NET 5, a pisane chyba było w .NET Core 2.1. Może coś nakieruje ;-)
@AdamWox: mam to bardzo podobnie zrobione. Jednak jak zarejestrujesz DbContext jako DbContextPool to wtedy nie otrzymasz kontekstu użytkownika wstrzykując IHttpContextAccessor.
Robisz tak: W twoim dbcontext wystawiasz metode na ustawienie IHttpContextAccessor + jakieś pole na to.
Robisz klase Np DbContextProvider zarejestrowana jako Scoped. Tak klasa Ma wstrzyknięty dbcontext zarejestrowany jako pool. DbContextProvider przed zwróceniem ustawia odpowiedni IHttpContextAccessor w Dbcontext. Reszte jak u @AdamWox. To tak na szybko jakbym miał coś kombinować.