# CQRS Validation with MediatR Pipeline and FluentValidation

> I consider input and business validation differently, and each deserves a specific solution. I want to show you an elegant solution for validation using MediatR and FluentValidation. If you aren't using CQRS with MediatR, everything here adapts to other paradigms.

Published: 2023-09-30. Author: Milan Jovanović.

Canonical: https://milanjovanovic.tech/blog/cqrs-validation-with-mediatr-pipeline-and-fluentvalidation

You validate CQRS commands with a MediatR `IPipelineBehavior` that runs FluentValidation validators before the handler executes.
Input validation only checks that the command is processable, while business validation reads the system state to check business rules.
A middleware turns the resulting `ValidationException` into a `ProblemDetails` response with status 400.

Validation is an essential [**cross-cutting concern**](https://milanjovanovic.tech/blog/balancing-cross-cutting-concerns-in-clean-architecture) that you need to solve in your application.
You want to ensure the request is valid before you consider processing it.

Another important question you need to answer is how you approach different types of validation.
For example, I consider input and business validation differently, and each deserves a specific solution.

I want to show you an elegant solution for validation using [MediatR](https://github.com/jbogard/MediatR)
and [FluentValidation.](https://docs.fluentvalidation.net/en/latest/index.html)

If you aren't using [CQRS](https://learn.microsoft.com/en-us/azure/architecture/patterns/cqrs) with MediatR, don't worry.
Everything I explain about validation can easily be adapted to other paradigms.

Here's what I'm going to talk about in this week's newsletter:

- Standard validation approach
- Input vs business validation
- Separating validation logic
- Generic `ValidationBehavior`

Let's dive in.

## The Standard Command Validation Approach

The standard way of implementing validation is right before processing the command.
The validation is tightly coupled to the command handler, which could be problematic.

I find this approach difficult to maintain as the complexity of the validation increases.
Each change to the validation logic also touches the handler, and the handler itself can grow out of control.

It also makes it harder to differentiate between input and _business_ validation.

Here's an example `ShipOrderCommandHandler` that checks if the `ShippingAddress.Country` is one of the supported countries:

```csharp
internal sealed class ShipOrderCommandHandler
    : IRequestHandler<ShipOrderCommand>
{
    private readonly IOrderRepository _orderRepository;
    private readonly IShippingService _shippingService;
    private readonly ShipmentSettings _shipmentSettings;

    public async Task Handle(
        ShipOrderCommand command,
        CancellationToken cancellationToken)
    {
        if (!_shipmentSettings
                .SupportedCountries
                .Contains(command.ShippingAddress.Country))
        {
            throw new ArgumentException(nameof(ShipOrderCommand.Address));
        }

        var order = _orderRepository.Get(command.OrderId);

        _shippingService.ShipTo(
            command.ShippingAddress,
            command.ShippingMethod);
    }
}
```

What if we can separate command validation and command handling?

## Input Validation and Business Validation

I mentioned input and _business_ validation in the previous section.

Here's how I consider them to be different:

- **Input validation** - We only validate that the command is _processable_.
  These are simple validations, such as checking for `null` values, empty strings, etc.
- **Business validation** - We validate the command to satisfy the business rules.
  This includes checking the system state for required preconditions before processing the command.

Another way to compare them is cheap vs. expensive.
Input validation is usually cheap to execute and can be done in memory.
While business validation involves reading state and is slower.

So, input validation sits at the entry point of the use case before handling the request.
After it completes, we have a _valid_ command.
And this is a rule I always follow - an invalid command should never reach the handler.

## Input Validation With FluentValidation

[FluentValidation](https://docs.fluentvalidation.net/en/latest/index.html) is an excellent validation library for .NET,
which uses a fluent interface and lambda expressions for building strongly typed validation rules.

Here's the `ShipOrderCommand` that we want to validate:

```csharp
public sealed record ShipOrderCommand : IRequest
{
    public Guid OrderId { get; set; }

    public string ShippingMethod { get; set; }

    public Address ShippingAddress { get; set; }
}
```

To implement a validator with [FluentValidation,](https://github.com/FluentValidation/FluentValidation)
you create a class that inherits from the `AbstractValidator<T>` base class.
Then, you can add the validation rules from the constructor using `RuleFor`:

```csharp
public sealed class ShipOrderCommandValidator
    : AbstractValidator<ShipOrderCommand>
{
    public ShipOrderCommandValidator(ShipmentSettings settings)
    {
        RuleFor(command => command.OrderId)
            .NotEmpty()
            .WithMessage("The order identifier can't be empty.");

        RuleFor(command => command.ShippingMethod)
            .NotEmpty()
            .WithMessage("The shipping method can't be empty.");

        RuleFor(command => command.ShippingAddress)
            .NotNull()
            .WithMessage("The shipping address can't be empty.");

        RuleFor(command => command.ShippingAddress.Country)
            .Must(country => settings.SupportedCountries.Contains(country))
            .WithMessage("The shipping country isn't supported.");
    }
}
```

The naming convention I like to use is the name of the command and append _Validator_.
You can also enforce this by writing [architecture tests.](https://milanjovanovic.tech/blog/enforcing-software-architecture-with-architecture-tests)

To automatically register all validators from an assembly, you need to call the `AddValidatorsFromAssembly` method:

```csharp
services.AddValidatorsFromAssembly(ApplicationAssembly.Assembly);
```

## Running Validation From the Use Case

To run the `ShipOrderCommandValidator`, you can use the `IValidator<T>` service and inject it from the constructor.

The validator exposes a few methods you can call, like `Validate`, `ValidateAsync`, or `ValidateAndThrow`.

The `Validate` method returns a `ValidationResult` object which contains two properties:

- `IsValid` - a boolean flag saying whether the validation succeeded
- `Errors` - a collection of `ValidationFailure` objects containing any validation failures

Alternatively, calling the `ValidateAndThrow` method throws a `ValidationException` if validation fails.

```csharp
internal sealed class ShipOrderCommandHandler
    : IRequestHandler<ShipOrderCommand>
{
    private readonly IOrderRepository _orderRepository;
    private readonly IShippingService _shippingService;
    private readonly IValidator<ShipOrderCommand> _validator;

    public async Task Handle(
        ShipOrderCommand command,
        CancellationToken cancellationToken)
    {
        _validator.ValidateAndThrow(command);

        var order = _orderRepository.Get(command.OrderId);

        _shippingService.ShipTo(
            command.ShippingAddress,
            command.ShippingMethod);
    }
}
```

This approach forces you to define an explicit dependency on `IValidator` in every command handler.

What if we can implement this cross-cutting concern in a more generic way?

## MediatR Validation Pipeline

Here's a complete implementation of a `ValidationBehavior` using FluentValidation and [**MediatR's `IPipelineBehavior`**](https://milanjovanovic.tech/blog/mediatr-pipeline-behaviors).

The `ValidationBehavior` acts as a middleware for the request pipeline and performs validation.
If the validation fails, it will throw a custom `ValidationException` with a collection of `ValidationError` objects.

I also want to highlight the use of `ValidateAsync`, which allows you to define asynchronous validation rules.
You must call the `ValidateAsync` method if you have asynchronous rules.
Otherwise, the validator will throw an exception.

```csharp
public sealed class ValidationBehavior<TRequest, TResponse>
    : IPipelineBehavior<TRequest, TResponse>
    where TRequest : ICommandBase
{
    private readonly IEnumerable<IValidator<TRequest>> _validators;

    public ValidationBehavior(IEnumerable<IValidator<TRequest>> validators)
    {
        _validators = validators;
    }

    public async Task<TResponse> Handle(
        TRequest request,
        RequestHandlerDelegate<TResponse> next,
        CancellationToken cancellationToken)
    {
        var context = new ValidationContext<TRequest>(request);

        var validationFailures = await Task.WhenAll(
            _validators.Select(validator => validator.ValidateAsync(context)));

        var errors = validationFailures
            .Where(validationResult => !validationResult.IsValid)
            .SelectMany(validationResult => validationResult.Errors)
            .Select(validationFailure => new ValidationError(
                validationFailure.PropertyName,
                validationFailure.ErrorMessage))
            .ToList();

        if (errors.Any())
        {
            throw new Exceptions.ValidationException(errors);
        }

        var response = await next();

        return response;
    }
}
```

Don't forget to register the `ValidationBehavior` with MediatR by calling `AddOpenBehavior`:

```csharp
services.AddMediatR(config =>
{
    config.RegisterServicesFromAssemblyContaining<ApplicationAssembly>();

    config.AddOpenBehavior(typeof(ValidationBehavior<,>));
});
```

## Handling Validation Exceptions

Here's a custom `ValidationExceptionHandlingMiddleware` middleware that only handles the custom `ValidationException`.
It converts the exception to a `ProblemDetails` response and includes any validation errors.

You can easily expand this to be a [**generic global exception handler**](https://milanjovanovic.tech/blog/global-error-handling-in-aspnetcore-8).

```csharp
public sealed class ValidationExceptionHandlingMiddleware
{
    private readonly RequestDelegate _next;

    public ValidationExceptionHandlingMiddleware(RequestDelegate next)
    {
        _next = next;
    }

    public async Task InvokeAsync(HttpContext context)
    {
        try
        {
            await _next(context);
        }
        catch (Exceptions.ValidationException exception)
        {
            var problemDetails = new ProblemDetails
            {
                Status = StatusCodes.Status400BadRequest,
                Type = "ValidationFailure",
                Title = "Validation error",
                Detail = "One or more validation errors has occurred"
            };

            if (exception.Errors is not null)
            {
                problemDetails.Extensions["errors"] = exception.Errors;
            }

            context.Response.StatusCode = StatusCodes.Status400BadRequest;

            await context.Response.WriteAsJsonAsync(problemDetails);
        }
    }
}
```

You also need to include the middleware in the request pipeline by calling `UseMiddleware`:

```csharp
app.UseMiddleware<ExceptionHandlingMiddleware>();
```

## Takeaway

This implementation of `ValidationBehavior` is something I use in real projects, and it works incredibly well.
If I don't want to throw an exception, I can update the `ValidationBehavior` to return a result object instead.

How do you apply this if you're not using MediatR?

I'm using an `IPipelineBehavior`, which allows me to implement a _middleware_ wrapping each request.

So, all you need is a way to implement middleware and place your validation inside.
And I like having options, so here are [three ways to create middleware in ASP.NET Core.](https://milanjovanovic.tech/blog/3-ways-to-create-middleware-in-asp-net-core)

Hope this was valuable.

Stay awesome!

---

## Frequently asked questions

### What is the difference between input validation and business validation?

Input validation only checks that a command is processable: null checks, empty strings, and similar rules that run cheaply in memory. Business validation checks the system state against business rules, which involves reading data and is slower. An invalid command should never reach the handler.

### How do I validate commands with FluentValidation?

Create a class inheriting from AbstractValidator<T> and define strongly typed rules in the constructor with RuleFor. Register all validators from an assembly with AddValidatorsFromAssembly, then run them with Validate, ValidateAsync, or ValidateAndThrow through the IValidator<T> service.

### How do I add validation to the MediatR pipeline?

Implement IPipelineBehavior<TRequest, TResponse> as a ValidationBehavior that resolves all validators for the request, runs them with ValidateAsync, and throws a ValidationException when any rule fails. Register it with AddOpenBehavior so it wraps every request like middleware.

### How do I return FluentValidation errors as an HTTP response?

Add a custom middleware that catches the ValidationException, converts it into a ProblemDetails response with status 400, and attaches the validation errors as an extension property. Register it in the request pipeline with UseMiddleware.

### Can I use this validation approach without MediatR?

Yes. The IPipelineBehavior is just a middleware wrapping each request, so all you need is another way to implement middleware and place the validation inside it. The split between input validation and business validation applies to any paradigm.
