Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

FluentValidation use custom IActionFilter

I have a custom IActionFilter which I register with my application like so:

services.AddControllers(options => options.Filters.Add(new HttpResponseExceptionFilter()));

The class looks like this:

public class HttpResponseExceptionFilter : IActionFilter, IOrderedFilter
{
    public int Order { get; set; } = int.MaxValue - 10;

    public void OnActionExecuting(ActionExecutingContext context)
    {
    }

    public void OnActionExecuted(ActionExecutedContext context)
    {
        if (context.Exception == null) return;

        var attempt = Attempt<string>.Fail(context.Exception);

        if (context.Exception is AttemptException exception)
        {
            context.Result = new ObjectResult(attempt)
            {
                StatusCode = exception.StatusCode,
            };
        }
        else
        {
            context.Result = new ObjectResult(attempt)
            {
                StatusCode = (int)HttpStatusCode.InternalServerError,
            };
        }

        context.ExceptionHandled = true;
    }
}

I would expect that when validating it would invoke the OnActionExecuting method. So I added this code:

public void OnActionExecuting(ActionExecutingContext context)
{
    if (!context.ModelState.IsValid)
    {
        context.Result = new BadRequestObjectResult(context.ModelState);
    }
}

And I put a breakpoint at the start of the method, but when I run my application and try to post an invalid model, I get this response:

{
    "errors": {
        "Url": [
            "'Url' is invalid. It should start with 'https://www.youtube.com/embed'",
            "'Url' is invalid. It should have the correct parameter '?start='"
        ]
    },
    "type": "https://tools.ietf.org/html/rfc7231#section-6.5.1",
    "title": "One or more validation errors occurred.",
    "status": 400,
    "traceId": "|87e96062-42181357ba1ef8c5."
}

How can I force FluentValidation to use my filter?

like image 657
r3plica Avatar asked Jun 17 '26 19:06

r3plica


2 Answers

When [ApiController] attribute is applied ,ASP.NET Core automatically handles model validation errors by returning a 400 Bad Request with ModelState as the response body :

Automatic HTTP 400 responses

To disable the automatic 400 behavior, set the SuppressModelStateInvalidFilter property to true :

services.AddControllers()
    .ConfigureApiBehaviorOptions(options => 
    {   
        options.SuppressModelStateInvalidFilter = true;     
    });
like image 80
Nan Yu Avatar answered Jun 19 '26 09:06

Nan Yu


The best solution I found was:

.ConfigureApiBehaviorOptions(options =>
{
    options.InvalidModelStateResponseFactory = context =>
    {
        var messages = context.ModelState.Values
            .Where(x => x.ValidationState == ModelValidationState.Invalid)
            .SelectMany(x => x.Errors)
            .Select(x => x.ErrorMessage)
            .ToList();

        return new BadRequestObjectResult(
            Attempt<string>.Fail(
                new AttemptException(string.Join($"{Environment.NewLine}", messages))));
    };
})
like image 27
r3plica Avatar answered Jun 19 '26 09:06

r3plica