RCommon
HomeGitHub
  • Introduction
  • Common Scenarios
  • Getting Started
    • Running Examples
    • Roadmap
    • Releases
      • 1.0.1.75
      • 1.0.2.0
      • 2.0.0
      • 2.1.0
  • Topics
    • Fundamentals
      • Configuration
      • Logging
      • GUID Generation
      • Time and Date
      • Emailing
        • SMTP Email
        • SendGrid Email API
      • Data Transfer Objects
        • Pagination
      • Security
        • Current User
        • Claims
      • Events
        • Transactional Events
        • Synchronous Events
        • Asynchronous Events
        • Producers
        • Subscribers
      • Validation
        • Fluent Validation
      • Caching
        • Dynamically Compiled Expressions
        • Persistence Caching
        • Caching Services
        • Redis & Valkey
        • Memory Cache
      • Serialization
        • JSON.NET
        • System.Text.Json
    • Patterns
      • Specification
      • Mediator
        • MediatR
          • Validator Behavior
          • Unit of Work Behavior
          • Logging Behavior
      • CQRS
        • Commands
        • Queries
      • Persistence
        • Repository
          • Entity Framework Core
          • Dapper
          • Linq2Db
        • Transactions
          • Unit of Work
      • Event Bus
        • In Memory
        • MediatR
        • Wolverine
      • Message Bus
        • MassTransit
        • Wolverine
    • Architecture
      • Overview
      • Microservices
      • Clean Architecture
      • Event Driven Architecture
  • Examples
    • Clean Architecture
    • CQRS
    • Mediator: MediatR
    • Event Handling: In Memory
    • Event Handling: MediatR
    • Event Handling: MassTransit
    • Event Handling: Wolverine
    • Validation: Fluent Validation
Powered by GitBook
On this page
  • Implementation
  • Usage
  1. Topics
  2. Patterns
  3. Mediator
  4. MediatR

Unit of Work Behavior

Unit of Work behavior in MediatR pipeline within RCommon.

PreviousValidator BehaviorNextLogging Behavior

Last updated 9 months ago

The 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 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

public class UnitOfWorkRequestBehavior<TRequest, TResponse> : IPipelineBehavior<TRequest, TResponse>
    where TRequest : IRequest
{
    private readonly ILogger<UnitOfWorkRequestBehavior<TRequest, TResponse>> _logger;
    private readonly IUnitOfWorkFactory _unitOfWorkScopeFactory;

    public UnitOfWorkRequestBehavior(IUnitOfWorkFactory unitOfWorkScopeFactory,
        ILogger<UnitOfWorkRequestBehavior<TRequest, TResponse>> logger)
    {
        _unitOfWorkScopeFactory = unitOfWorkScopeFactory ?? throw new ArgumentException(nameof(IUnitOfWorkFactory));
        _logger = logger ?? throw new ArgumentException(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 = await next(); // 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;
        }
    }
}

Usage

builder.Services.AddRCommon()
    .WithMediator<MediatRBuilder>(mediator =>
    {
        // Conventional dependency injection w/ MediatR
        mediator.Configure(config =>
        {
            config.RegisterServicesFromAssemblies((typeof(ApplicationServicesRegistration).GetTypeInfo().Assembly));
        });
        
        // Utilizing MediatR pipeline registrations
        mediator.AddUnitOfWorkToRequestPipeline();
    });
unit of work behavior
Persistence