.NET Learning Notes: Auto Parameters Validator
Though FluentValidation.AspNetCore is not maintained, we can still integrate FluentValidation with a custom action filter to achieve automatic validation. 1.Install FluentValidation NuGet Package dotnet add package FluentValidation 2.Create Your Validator Classes public record UpdateCategoryRequest(long CategoryId, string? Name, string? Description); public class UpdateCategoryRequestValidator : AbstractValidator { public UpdateCategoryRequestValidator() { RuleFor(x => x.CategoryId).NotEmpty(); RuleFor(x => x) .Must(x => !string.IsNullOrWhiteSpace(x.Name) || !string.IsNullOrWhiteSpace(x.Description)) .WithMessage("Either Name or Description must be provided"); } } 3.Create a Custom Action Filter for Validation public class ValidationFilter(IServiceProvider serviceProvider) : IAsyncActionFilter { public async Task OnActionExecutionAsync(ActionExecutingContext context, ActionExecutionDelegate next) { foreach (var arg in context.ActionArguments) { var argumentType = arg.Value?.GetType(); if (argumentType == null) continue; // Create a type, for example, Class A -> IValidator var validatorType = typeof(IValidator).MakeGenericType(argumentType); var validator = serviceProvider.GetService(validatorType); if (validator is IValidator val) { // Invoke Validate method var validationResult = await val.ValidateAsync(new ValidationContext(arg.Value!)); if (!validationResult.IsValid) { var errors = validationResult.Errors.Select(x => x.ErrorMessage).ToList(); context.Result = new BadRequestObjectResult( new ResponseData(ApiResponseCode.ParameterError, errors)); return; } } } await next(); } } 4.Register the Validator and ActionFilter builder.Services.AddValidatorsFromAssemblyContaining(); builder.Services.AddControllers(options => { options.Filters.Add(order: 1); options.Filters.Add(order: 2); options.Filters.Add(order: 3); }); All Done! Why do not we pass context when we invoke the validator.Valiadte() method? There is a extension method to automatic create context. FluentValidation assumes the context to be the instance of the object being validated and automatically creates the necessary ValidationContext when you call validator.Validate(instance). This is the default and most common use case. public static ValidationResult Validate(this IValidator validator, T instance, Action options) => validator.Validate(ValidationContext.CreateWithOptions(instance, options));

Though FluentValidation.AspNetCore is not maintained, we can still integrate FluentValidation with a custom action filter to achieve automatic validation.
1.Install FluentValidation NuGet Package
dotnet add package FluentValidation
2.Create Your Validator Classes
public record UpdateCategoryRequest(long CategoryId, string? Name, string? Description);
public class UpdateCategoryRequestValidator : AbstractValidator
{
public UpdateCategoryRequestValidator()
{
RuleFor(x => x.CategoryId).NotEmpty();
RuleFor(x => x)
.Must(x => !string.IsNullOrWhiteSpace(x.Name)
|| !string.IsNullOrWhiteSpace(x.Description))
.WithMessage("Either Name or Description must be provided");
}
}
3.Create a Custom Action Filter for Validation
public class ValidationFilter(IServiceProvider serviceProvider) : IAsyncActionFilter
{
public async Task OnActionExecutionAsync(ActionExecutingContext context, ActionExecutionDelegate next)
{
foreach (var arg in context.ActionArguments)
{
var argumentType = arg.Value?.GetType();
if (argumentType == null) continue;
// Create a type, for example, Class A -> IValidator
var validatorType = typeof(IValidator<>).MakeGenericType(argumentType);
var validator = serviceProvider.GetService(validatorType);
if (validator is IValidator val)
{
// Invoke Validate method
var validationResult = await val.ValidateAsync(new ValidationContext
4.Register the Validator and ActionFilter
builder.Services.AddValidatorsFromAssemblyContaining();
builder.Services.AddControllers(options =>
{
options.Filters.Add(order: 1);
options.Filters.Add(order: 2);
options.Filters.Add(order: 3);
});
All Done!
Why do not we pass context when we invoke the validator.Valiadte() method?
There is a extension method to automatic create context. FluentValidation assumes the context to be the instance of the object being validated and automatically creates the necessary ValidationContext when you call validator.Validate(instance). This is the default and most common use case.
public static ValidationResult Validate(this IValidator validator, T instance, Action> options)
=> validator.Validate(ValidationContext.CreateWithOptions(instance, options));