FluentValidation · How it works
1 min readRapid overview
How it works
This note covers how to use FluentValidation properly and what a senior C#/.NET developer needs to know: core concepts, best practices, integration with ASP.NET Core, testing, performance, and advanced extension points.
Core concepts and API
- Create a validator by implementing
AbstractValidator<T>. - Add rules with
RuleFor(x => x.Property).NotEmpty().Length(5, 50).Must(...); - Supports
When,Unless,CascadeModeandRuleSetfor conditional and grouped validation. - Validators support async via
MustAsync, customIValidator<T>implementations, andSetValidatorto compose nested validators.
Example:
public class CreateOrderDto
{
public string Symbol { get; set; }
public decimal Amount { get; set; }
public string CustomerId { get; set; }
}
public class CreateOrderDtoValidator : AbstractValidator<CreateOrderDto>
{
private readonly ILeaveTypeRepository _leaveTypeRepository;
public CreateOrderDtoValidator(ILeaveTypeRepository leaveTypeRepository)
{
CascadeMode = CascadeMode.Stop;
RuleFor(x => x.Symbol)
.NotEmpty()
.Length(3, 10);
RuleFor(x => x.Amount)
.GreaterThan(0);
RuleFor(x => x.CustomerId)
.NotEmpty()
.MustAsync(async (id, ct) => await CustomerExists(id))
.WithMessage("Customer does not exist");
// Example of nested validator
RuleFor(x => x.Address).SetValidator(new AddressValidator());
RuleFor(q => q)
.MustAsync(LeaveTypeNameUnique).WithMessage("Leave type already exists");
_leaveTypeRepository = leaveTypeRepository;
}
private async Task<bool> LeaveTypeNameUnique(CreateLeaveTypeCommand command, CancellationToken token)
{
return await _leaveTypeRepository.IsLeaveTypeUniqe(command.Name);
}
}