ValidationBehavior
Namespace: RA.Utilities.Feature.Behaviors
The ValidationBehavior is an implementation of the IPipelineBehavior interface that automatically validates incoming requests using FluentValidation.
🎯 Purpose
ValidationBehavior is a crucial implementation of the IPipelineBehavior interface.
The primary purpose of the ValidationBehavior is to act as a validation gatekeeper for the CQRS pipeline.
It ensures that no request reaches its handler unless it passes all defined validation rules.
This is a critical component for building robust and secure applications.
🔑 Key Benefits:
- Clean Handlers: Your
IRequestHandlerimplementations are freed from the responsibility of validation, allowing them to focus purely on business logic. - Short-Circuiting: If validation fails, the behavior immediately stops the pipeline and throws a
BadRequestException. The handler is never executed with invalid data. - Centralized Logic: Validation rules are defined in dedicated
FluentValidationclasses, keeping them separate from the business logic and making them easy to manage and reuse. - Consistent Errors: It guarantees that all validation failures across the application result in a consistent, predictable error response format (the API layer's
GlobalExceptionHandlerconverts the thrownBadRequestExceptioninto a400 Bad Requestresponse carrying the structuredValidationErrorentries).
⚙️ How It Works
The behavior is registered in the dependency injection container as part of the CQRS pipeline. For every request sent through the mediator:
- Intercepts the Request: The
ValidationBehaviorintercepts theIRequestbefore it reaches its handler. - Resolves Validators: It resolves all registered
IValidator<TRequest>implementations for the specific request type from the DI container. - Executes Validation: It runs the
ValidateAsyncmethod on all resolved validators. - Checks the Outcome:
- If there are no validation errors, it calls
await next()to pass the request along the pipeline. - If there are validation errors, it throws a
BadRequestExceptionbuilt from the collected failures (viaValidationUtilities.CreateValidationErrorResult). Invalid data never reaches your handler.
- If there are no validation errors, it calls
🚀 Usage Example
To use the behavior, you need to:
1. Create a Validator:
Define a validator for your command or query using FluentValidation.
public class CreateProductCommandValidator : AbstractValidator<CreateProductCommand>
{
public CreateProductCommandValidator()
{
RuleFor(x => x.Name).NotEmpty();
RuleFor(x => x.Price).GreaterThan(0);
}
}
2. Register Services
In your Program.cs, register the feature with its validator using the fluent builder.
// Program.cs
using RA.Utilities.Feature.Extensions;
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddMediator();
builder.Services
.AddFeature<CreateProductCommand, int, CreateProductHandler>()
.AddValidator<CreateProductCommandValidator>();
With this setup, any CreateProductCommand sent through the mediator will be automatically validated — and if it is invalid, ValidationBehavior throws a BadRequestException before the handler runs.