Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

ModelState from ActionFilter - ASP .NET Core 2.1 API

I need to catch the errors from the "ModelState" to send a personalized message. The problem is that the filter is never executed if a property of the UserDTO has the attribute "Required". If you remove it, enter the filter, but the modelState is valid

[HttpPost]
[ModelState]
public IActionResult Post([FromBody] UserDTO currentUser)
{
    /*if (!ModelState.IsValid)
    {
        return BadRequest();
    }*/
    return Ok();
}

public class ModelStateAttribute : ActionFilterAttribute
{
    public override void OnActionExecuting(ActionExecutingContext currentContext)
    {
        if (!currentContext.ModelState.IsValid)
        {
            currentContext.Result = new ContentResult
            {
                Content = "Modelstate not valid",
                StatusCode = 400
            };
        }
        else
        {
            base.OnActionExecuting(currentContext);
        }
    }
}

public class UserDTO
{
    [Required]
    public string ID { get; set; }

    public string Name { get; set; }

}
like image 828
avechuche Avatar asked Jul 06 '18 22:07

avechuche


2 Answers

Your issue is caused by a new feature Automatic HTTP 400 responses:

Validation errors automatically trigger an HTTP 400 response.

So, if you want to custom the Validation errors, you need to disable this feature.

The default behavior is disabled when the SuppressModelStateInvalidFilter property is set to true. Add the following code in Startup.ConfigureServices after services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_1);

    services.Configure<ApiBehaviorOptions>(options => {    
options.SuppressModelStateInvalidFilter = true;  });
like image 187
Edward Avatar answered Sep 18 '22 00:09

Edward


In ASP.NET Core 2.1 you also can change validation error response with InvalidModelStateResponseFactory parameter in ConfigureServices at Startup.cs:

services.Configure<ApiBehaviorOptions>(options =>
    options.InvalidModelStateResponseFactory = actionContext =>
        new BadRequestObjectResult(
            new
            {
                error = string.Join(
                    Environment.NewLine,
                    actionContext.ModelState.Values.SelectMany(v => v.Errors.Select(x => x.ErrorMessage)).ToArray()
                )
            }
        )
);

For example this configuration returns object with error field where combined all validation errors. In that case ValidationAttribute is not needed, but you should decorate your controller with [ApiController] attribute.

like image 29
Victor Trusov Avatar answered Sep 22 '22 00:09

Victor Trusov