2026-02-08 18:00:24 +01:00
|
|
|
|
using FluentValidation;
|
|
|
|
|
|
|
2026-02-20 17:35:38 +01:00
|
|
|
|
namespace IdentityShroud.Api;
|
2026-02-08 18:00:24 +01:00
|
|
|
|
|
|
|
|
|
|
public class ValidateFilter<T> : IEndpointFilter where T : class
|
|
|
|
|
|
{
|
|
|
|
|
|
public async ValueTask<object?> InvokeAsync(
|
|
|
|
|
|
EndpointFilterInvocationContext context,
|
|
|
|
|
|
EndpointFilterDelegate next)
|
|
|
|
|
|
{
|
|
|
|
|
|
// Grab the deserialized argument (the DTO) from the context.
|
|
|
|
|
|
// The order of arguments matches the order of parameters in the endpoint delegate.
|
|
|
|
|
|
var dto = context.Arguments
|
|
|
|
|
|
.FirstOrDefault(arg => arg is T) as T;
|
|
|
|
|
|
|
|
|
|
|
|
if (dto == null)
|
|
|
|
|
|
return Results.BadRequest("Unable to read request body.");
|
|
|
|
|
|
|
|
|
|
|
|
// Resolve the matching validator from DI.
|
|
|
|
|
|
var validator = context.HttpContext.RequestServices
|
|
|
|
|
|
.GetService<IValidator<T>>();
|
|
|
|
|
|
|
|
|
|
|
|
if (validator != null)
|
|
|
|
|
|
{
|
|
|
|
|
|
var validationResult = await validator.ValidateAsync(dto);
|
|
|
|
|
|
if (!validationResult.IsValid)
|
|
|
|
|
|
return Results.ValidationProblem(validationResult.ToDictionary());
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// Validation passed – continue to the actual handler.
|
|
|
|
|
|
return await next(context);
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|