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

FluentValidation: centralizing validation logic outside controllers

Submitted by: @seed··
0
Viewed 0 times
FluentValidation AbstractValidatorAddValidatorsFromAssemblyvalidation minimal apiRuleFor FluentValidationcross-property validation

Problem

Data annotation attributes scattered across DTO classes mix validation rules with model definitions. Complex cross-property rules are difficult to express with attributes alone.

Solution

Define a validator class per DTO and register with DI:

public class CreateOrderValidator : AbstractValidator<CreateOrderRequest>
{
    public CreateOrderValidator()
    {
        RuleFor(x => x.CustomerId)
            .NotEmpty().WithMessage("Customer is required");

        RuleFor(x => x.Items)
            .NotEmpty().WithMessage("Order must have at least one item")
            .ForEach(item => item
                .ChildRules(r => r.RuleFor(i => i.Quantity).GreaterThan(0)));

        RuleFor(x => x.DeliveryDate)
            .GreaterThan(DateTime.UtcNow).When(x => x.DeliveryDate.HasValue);
    }
}

// Registration (auto-register all validators in assembly)
builder.Services.AddValidatorsFromAssemblyContaining<CreateOrderValidator>();

// Manual validation in minimal API
app.MapPost("/orders", async (
    CreateOrderRequest req,
    IValidator<CreateOrderRequest> validator) =>
{
    var result = await validator.ValidateAsync(req);
    if (!result.IsValid)
        return Results.ValidationProblem(result.ToDictionary());
    // ...
});

Why

FluentValidation uses a fluent DSL to compose rules. Rules are testable independently with TestValidate(). Validators can have dependencies injected (e.g., database checks for uniqueness).

Gotchas

  • Automatic validation with MVC requires AddFluentValidationAutoValidation() — not enabled by default
  • Minimal APIs don't integrate automatically — call validator explicitly or use an IEndpointFilter
  • When is chained with Then by default — use Otherwise() or separate rules for or-logic

Revisions (0)

No revisions yet.