Extensii și pattern-uri suplimentare în CQRS
După ce o arhitectură CQRS este stabilă, următorul pas natural este rafinarea ei prin extensii și pattern-uri care o fac mai robustă, mai testabilă și mai ușor de întreținut. În această etapă, ne concentrăm pe trei direcții-cheie: decoratori peste MediatR, event publishing și audit logging. Toate acestea adresează nevoi comune ale aplicațiilor enterprise, fără să compromită separarea clară dintre comenzi și interogări.
🎯 1. Decorators peste MediatR pentru Logging, Retry și Validation
Unul dintre cele mai elegante moduri de a introduce comportamente comune în pipeline-ul aplicației este prin decoratori. În ecosistemul MediatR, acest lucru se realizează prin implementarea interfeței IPipelineBehavior<TRequest, TResponse>.
Această interfață acționează ca un middleware care interceptează toate cererile trimise către MediatR, permițând adăugarea logicilor cross-cutting – adică funcționalități care traversează mai multe componente, precum:
- 
Logging – urmărirea cererilor și răspunsurilor pentru depanare și monitorizare;
 - 
Retry – reexecutarea unei comenzi în caz de erori tranzitorii;
 - 
Validation – validarea cererilor înainte de procesare.
 
Exemplu simplu de decorator pentru logging:
public class LoggingBehavior<TRequest, TResponse> : IPipelineBehavior<TRequest, TResponse>
{
    private readonly ILogger<LoggingBehavior<TRequest, TResponse>> _logger;
    public LoggingBehavior(ILogger<LoggingBehavior<TRequest, TResponse>> logger)
        => _logger = logger;
    public async Task<TResponse> Handle(
        TRequest request, 
        RequestHandlerDelegate<TResponse> next, 
        CancellationToken cancellationToken)
    {
        _logger.LogInformation("Handling {Request}", typeof(TRequest).Name);
        var response = await next();
        _logger.LogInformation("Handled {Request}", typeof(TRequest).Name);
        return response;
    }
}
Această abordare permite adăugarea de comportamente fără a „polua” handler-ele individuale. Cu un simplu services.AddTransient(typeof(IPipelineBehavior<,>), typeof(LoggingBehavior<,>));, toate comenzile și interogările beneficiază automat de logging centralizat.
📢 2. Event Publishing: Domain Events vs Integration Events
Evenimentele sunt o componentă naturală a modelului Domain-Driven Design, iar în contextul CQRS, ele capătă un rol major. În esență, vorbim despre două categorii:
- 
Domain Events – reprezintă ceva ce s-a întâmplat în interiorul domeniului. De exemplu, PostCreatedDomainEvent poate fi declanșat atunci când o postare nouă este creată.
 - 
Integration Events – sunt utilizate pentru a notifica alte sisteme externe sau microservicii despre o schimbare. Ele traversează limitele aplicației.
 
Pentru Domain Events, MediatR oferă o integrare elegantă prin interfața INotification și handler-ele asociate INotificationHandler<TNotification>.
public class PostCreatedDomainEvent : INotification
{
    public Guid PostId { get; }
    public string Title { get; }
    public PostCreatedDomainEvent(Guid postId, string title)
    {
        PostId = postId;
        Title = title;
    }
}
public class PostCreatedEventHandler : INotificationHandler<PostCreatedDomainEvent>
{
    private readonly ILogger<PostCreatedEventHandler> _logger;
    public PostCreatedEventHandler(ILogger<PostCreatedEventHandler> logger) => _logger = logger;
    public Task Handle(PostCreatedDomainEvent notification, CancellationToken cancellationToken)
    {
        _logger.LogInformation("New post created: {Title}", notification.Title);
        return Task.CompletedTask;
    }
}
Astfel, domeniul rămâne coerent, iar logica de reacție la evenimente poate fi extinsă fără a afecta nucleul aplicației.
Pentru Integration Events, este recomandată o abordare asincronă – de exemplu, publicarea în RabbitMQ, Azure Service Bus sau Kafka – pentru a decupla complet comunicația între aplicații.
🧾 3. Audit Logging la comenzi
În multe aplicații enterprise, urmărirea acțiunilor utilizatorilor este o cerință obligatorie, mai ales în medii financiare, medicale sau guvernamentale. În CQRS, audit logging-ul poate fi implementat elegant tot printr-un pipeline behavior sau direct în handler-ele de comandă.
O abordare simplă presupune crearea unei entități AuditLog și salvarea evenimentelor într-o tabelă auxiliară sau într-un Event Store dedicat.
public class AuditBehavior<TRequest, TResponse> : IPipelineBehavior<TRequest, TResponse>
{
    private readonly IAuditService _auditService;
    public AuditBehavior(IAuditService auditService)
        => _auditService = auditService;
    public async Task<TResponse> Handle(
        TRequest request,
        RequestHandlerDelegate<TResponse> next,
        CancellationToken cancellationToken)
    {
        var response = await next();
        await _auditService.SaveAsync(request, response);
        return response;
    }
}
Prin această metodă, fiecare comandă trimisă prin MediatR lasă o urmă în baza de date – cu detalii despre cine a făcut acțiunea, când și ce s-a modificat.
Această transparență ajută la depanare, securitate și conformitate cu standarde precum GDPR sau ISO 27001.
🔚 Concluzie
Extensiile și pattern-urile din această etapă duc arhitectura CQRS la un nivel matur.
Prin decoratori, evenimente și audit logging, aplicația devine:
- 
Scalabilă – logica comună este centralizată;
 - 
Observabilă – toate acțiunile pot fi urmărite și analizate;
 - 
Ușor de extins – adăugarea unui nou comportament global nu afectează handler-ele existente.
 
CQRS nu înseamnă doar separarea dintre comenzi și interogări, ci și crearea unui cadru solid care facilitează mentenanța, auditul și extensibilitatea pe termen lung.
