Skip to main content

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:​

  1. Clean Handlers: Your IRequestHandler implementations are freed from the responsibility of validation, allowing them to focus purely on business logic.
  2. Short-Circuiting: If validation fails, the behavior immediately stops the pipeline and throws a BadRequestException. The handler is never executed with invalid data.
  3. Centralized Logic: Validation rules are defined in dedicated FluentValidation classes, keeping them separate from the business logic and making them easy to manage and reuse.
  4. Consistent Errors: It guarantees that all validation failures across the application result in a consistent, predictable error response format (the API layer's GlobalExceptionHandler converts the thrown BadRequestException into a 400 Bad Request response carrying the structured ValidationError entries).

⚙️ 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:

  1. Intercepts the Request: The ValidationBehavior intercepts the IRequest before it reaches its handler.
  2. Resolves Validators: It resolves all registered IValidator<TRequest> implementations for the specific request type from the DI container.
  3. Executes Validation: It runs the ValidateAsync method on all resolved validators.
  4. 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 BadRequestException built from the collected failures (via ValidationUtilities.CreateValidationErrorResult). Invalid data never reaches your handler.

🚀 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.