Unit of Work behavior in MediatR pipeline within RCommon.
The unit of work behavior is useful any time you want to de-couple your transaction handling from your application logic. It can be added by doing this in your dependency injection section. The Unit of Work behavior is really only useful when coupled with Persistence but should be used with the knowledge that all of your requests and the operations within will be wrapped with a transaction which could add some overhead to your application. That said, many enterprise applications have multi-step operations in most of their requests so this may be a good behavior to use.
Implementation
publicclassUnitOfWorkRequestBehavior<TRequest,TResponse> :IPipelineBehavior<TRequest,TResponse>whereTRequest:IRequest{privatereadonlyILogger<UnitOfWorkRequestBehavior<TRequest,TResponse>> _logger;privatereadonlyIUnitOfWorkFactory _unitOfWorkScopeFactory;publicUnitOfWorkRequestBehavior(IUnitOfWorkFactory unitOfWorkScopeFactory,ILogger<UnitOfWorkRequestBehavior<TRequest,TResponse>> logger) { _unitOfWorkScopeFactory = unitOfWorkScopeFactory ??thrownewArgumentException(nameof(IUnitOfWorkFactory)); _logger = logger ??thrownewArgumentException(nameof(ILogger)); } public async Task<TResponse> Handle(TRequest request, RequestHandlerDelegate<TResponse> next, CancellationToken cancellationToken)
{var response =default(TResponse);var typeName =request.GetGenericTypeName(); try {using (var unitOfWork =this._unitOfWorkScopeFactory.Create(TransactionMode.Default)) { _logger.LogInformation("----- Begin transaction {UnitOfWorkTransactionId} for {CommandName} ({@Command})",
unitOfWork.TransactionId, typeName, request); response =awaitnext(); // Let everything else in the request happen_logger.LogInformation("----- Commit transaction {UnitOfWorkTransactionId} for {CommandName}",unitOfWork.TransactionId, typeName);unitOfWork.Commit(); }return response; }catch (Exception ex) {_logger.LogError(ex,"ERROR Handling transaction for {CommandName} ({@Command})", typeName, request);throw; } }}