9

I have an ASP.NET Core API (.Net Core 2.1) and I implemented an Action Filter using this article

https://learn.microsoft.com/en-us/aspnet/core/mvc/controllers/filters?view=aspnetcore-2.1#action-filters

In my Model, I use Data Annotations to validate the model, and I added the ValidateModel attribute for the Action in my Controller.

    [HttpPost("CreateShipment")]
    [ValidateModel]
    public IActionResult CreateShipment([FromBody] CreateShipmentRequest request)
    {
         if (ModelState.IsValid)
         {
            //Do something
         }
         return Ok();
    }

I used Postman to test this, and my Action Filter gets called only if the Model is valid. If my request is missing a required field or some value is out of range, Action Filter doesn't get called. Instead I receive a 400 bad request with the model state in the response.

I implemented the Action Filter because I want to customize my model validation error. My understanding is that Action Filters get called at the time of model binding. Can someone help me figure out why this is happening and how to get the Action Filter to work?

UPDATE: I found the solution 2 seconds after posting the question, and the link @Silvermind posted below is great info too.

I added the following line to my Startup.cs

services.Configure<ApiBehaviorOptions>(options =>
{
     options.SuppressModelStateInvalidFilter = true;
});

It's well documented here on the Microsoft site. https://learn.microsoft.com/en-us/aspnet/core/web-api/index?view=aspnetcore-2.1#automatic-http-400-responses

3
  • 2
    Since .net core 2.1, an [ApiController] attribute is automatically placed on the controller. That does some things automatically; removing it solves this problem. Take a look at this post for more information: Exploring the ApiControllerAttribute and its features for ASP.NET Core MVC 2.1 Commented Mar 7, 2019 at 18:46
  • 1
    @Silvermind Thanks for the help. I actually found the solution my self a second before you posted this. I added the following in my Startup.cs in the ConfigureServices() services.Configure<ApiBehaviorOptions>(options => { options.SuppressModelStateInvalidFilter = true; }); Commented Mar 7, 2019 at 18:56
  • 1
    That's a nice solution. I suggest that you put it up as an answer instead of adding it to your question and accept your own answer. Commented Mar 7, 2019 at 21:31

3 Answers 3

14

Adding the following line to Startup.cs, ConfigureServices() method resolved the issue. turns out .Net Core has automatic 400 responses enabled by default. If you want to add custom Action Filters, you need to set those options at the startup.

services.Configure<ApiBehaviorOptions>(options =>
{
      options.SuppressModelStateInvalidFilter = true;
});

It's well documented here on the Microsoft site:

https://learn.microsoft.com/en-us/aspnet/core/web-api/index?view=aspnetcore-2.1#automatic-http-400-responses

Sign up to request clarification or add additional context in comments.

Comments

3

The [ApiController] attributes performs model validation automatically and triggers an HTTP response of 404, in .Net Core 3.0 you can chain to the new AddControllers() to suppress this feature:

services.AddControllers()
                .ConfigureApiBehaviorOptions(options =>
                {
                    options.SuppressModelStateInvalidFilter = true;
                });

Comments

1

The accepted answer disables the ModelStateInvalidFilter entirely, but if you'd still like to keep that validation behaviour, just run your custom action filter before it, you can do that by giving it a lower Order level than ModelStateInvalidFilter, which is defined as -2000 in its source code.

In other words, in the constructor of your action filter class, set the Order property (inherited from ActionFilterAttribute) to -3000 or something, and your filter will be called before ModelStateInvalidFilter.

public class MyFilterAttribute : ActionFilterAttribute {
    public MyFilterAttribute() {
        // Set this to anything lower than -2000
        Order = -3000;
    }

    public override void OnActionExecuting(ActionExecutingContext context) {
        base.OnActionExecuting(context);
        // Your custom code
    }
}

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.