Skip to content

Instantly share code, notes, and snippets.

@aradalvand
Last active May 12, 2023 06:04
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save aradalvand/d6fea70bc0c40f77f58ba276a31f4590 to your computer and use it in GitHub Desktop.
Save aradalvand/d6fea70bc0c40f77f58ba276a31f4590 to your computer and use it in GitHub Desktop.
FluentValidation filter for ASP.NET Core Minimal APIs
public static class AddValidationFilterExtension
{
public static TBuilder AddValidationFilter<TBuilder>(
this TBuilder builder
) where TBuilder : IEndpointConventionBuilder
{
return builder.AddEndpointFilterFactory((factoryCtx, next) =>
{
var sp = factoryCtx.ApplicationServices.GetRequiredService<IServiceProviderIsService>();
var validatableParameters = factoryCtx.MethodInfo.GetParameters()
.Select(p => new
{
p.Position,
ValidatorType = typeof(IValidator<>).MakeGenericType(p.ParameterType),
})
.Where(p => sp.IsService(p.ValidatorType))
.ToArray();
if (!validatableParameters.Any())
throw new InvalidOperationException($"No validatable parameters on '{factoryCtx.MethodInfo.Name}'.");
return async ctx =>
{
var validationResults = await Task.WhenAll(
validatableParameters.Select(p =>
{
var validator = (IValidator)ctx.HttpContext.RequestServices
.GetRequiredService(p.ValidatorType);
var objToValidate = ctx.Arguments[p.Position];
return validator.ValidateAsync(
new ValidationContext<object?>(objToValidate),
ctx.HttpContext.RequestAborted
);
})
);
if (validationResults.Any(r => !r.IsValid))
{
return Results.BadRequest(new
{
Errors = validationResults
.SelectMany(r => r.Errors)
.Select(e => e.ErrorMessage),
});
}
return await next(ctx);
};
});
}
}
// ...
app.MapGet("/", YourHandler)
.AddValidationFilter();
app.Run();
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment