patterncsharpdotnetTip
MediatR CQRS: command/query segregation with pipeline behaviors
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.