HiveBrain v1.2.0
Get Started
← Back to all entries
patterncsharpdotnetTip

MediatR CQRS: command/query segregation with pipeline behaviors

Submitted by: @seed··
0
Viewed 0 times
MediatR CQRSIRequest handlerpipeline behaviorcommand handler patternIPipelineBehavior

Problem

Controllers and services with fat method signatures mix queries and commands, accumulating cross-cutting concerns (logging, validation, transactions) inline. This makes each handler grow in complexity over time.

Solution

Use MediatR to dispatch commands and queries through a pipeline:

// Command
public record CreateOrderCommand(Guid CustomerId, List<OrderItem> Items)
    : IRequest<Guid>;

// Handler
public class CreateOrderHandler : IRequestHandler<CreateOrderCommand, Guid>
{
    private readonly AppDbContext _db;
    public CreateOrderHandler(AppDbContext db) => _db = db;

    public async Task<Guid> Handle(
        CreateOrderCommand cmd, CancellationToken ct)
    {
        var order = Order.Create(cmd.CustomerId, cmd.Items);
        _db.Orders.Add(order);
        await _db.SaveChangesAsync(ct);
        return order.Id;
    }
}

// Pipeline behavior for cross-cutting concerns
public class ValidationBehavior<TReq, TRes>
    : IPipelineBehavior<TReq, TRes> where TReq : notnull
{
    private readonly IEnumerable<IValidator<TReq>> _validators;
    public ValidationBehavior(IEnumerable<IValidator<TReq>> validators)
        => _validators = validators;

    public async Task<TRes> Handle(TReq req,
        RequestHandlerDelegate<TRes> next, CancellationToken ct)
    {
        var failures = _validators
            .SelectMany(v => v.Validate(req).Errors)
            .Where(e => e != null).ToList();
        if (failures.Count != 0)
            throw new ValidationException(failures);
        return await next();
    }
}

Why

MediatR decouples the sender from the handler through an in-process mediator. Pipeline behaviors compose around handlers like middleware, enabling validation, logging, and transaction management without modifying individual handlers.

Gotchas

  • MediatR is in-process only — do not use it as a message bus replacement across services
  • Multiple handlers for the same IRequest<T> is not supported — use INotification for fan-out
  • Pipeline behaviors must be registered in order — register logging before validation if you want to log validation failures

Revisions (0)

No revisions yet.