Extensions for ASP.NET Core
MIT License
Opinionated extensions for ASP.NET Core.
This package includes a validation filter that can be used with ASP.NET Minimal APIs to automatically validate incoming requests using FluentValidation.
For more information on the motivation behind this filter, see this blog post.
Install from Nuget.
dotnet add package O9d.AspNet.FluentValidation
Rather than attaching the filter to every endpoint, create a group under which your endpoints are created and add the validation filter:
var group = app.MapGroup("/")
.WithValidationFilter();
Automatic validation is opt-in and defaults to a strategy that uses the provided [Validate]
attribute:
group.MapPost("/things", ([Validate] DoSomething _) => Results.Ok());
public class DoSomething
{
public string? Name { get; set; }
public class Validator : AbstractValidator<DoSomething>
{
public Validator()
{
RuleFor(x => x.Name).NotEmpty();
}
}
}
If the request parameter is not valid, by default, a ValidationProblem
is returned with the HTTP status code 422 - Unprocessable Entity
{
"type": "https://tools.ietf.org/html/rfc4918#section-11.2",
"title": "One or more validation errors occurred.",
"status": 422,
"errors": {
"Name": ["'Name' must not be empty."]
}
}
A validation strategy determines how whether a parameter type is validateable. The default behaviour is to use the [Validate]
attribute which can be applied to the parameter (as above) or directly to the class. The library also includes support for the following:
You can choose to decorate the endpoints you wish to validate explicitly using metadata:
var group = app.MapGroup("/")
.WithValidationFilter(options => options.ShouldValidate = ValidationStrategies.HasValidationMetadata)
.RequireValidation(typeof(DoSomething));
group.MapPost("/things", (DoSomething _) => Results.Ok());
You need to specify the types that should be enlisted for validation so it generally only makes sense to do this at a group level.
My preferred approach is to define a marker interface e.g. IValidateable
and then decorate my input parameters with this:
var group = app.MapGroup("/")
.WithValidationFilter(options => options.ShouldValidate = ValidationStrategies.TypeImplements<IValidateable>());
group.MapPost("/things", (DoSomething _) => Results.Ok());
If none of the built-in strategies work for you, you can create your own implementation of the ValidationStrategy
delegate:
public delegate bool ValidationStrategy(ParameterInfo parameterInfo, IList<object> endpointMetadata);
You can override the default validation result by providing your own factory, which takes the FluentValidation ValidationResult
as an input:
var group = app.MapGroup("/")
.WithValidationFilter(options => options.InvalidResultFactory = validationResult => Results.BadRequest());
group.MapPost("/things", ([Validate] DoSomething _) => Results.Ok());