How to discern between model binding errors and model validation errors?

后端 未结 2 1285
傲寒
傲寒 2020-12-19 17:01

I\'m implementing a REST API project using ASP.NET Core MVC 2.0, and I\'d like to return a 400 status code if model binding failed (because the request is syntactically wron

相关标签:
2条回答
  • 2020-12-19 17:22

    Haven't checked option #1 yet, but:

    • ModelState.ValidationState has 4 possible values (Unvalidated, Invalid, Valid, Skipped) where in case of model binding errors I do get Unvalidated as a value
    • Also would consider using ApiBehaviorOptions (see sample here) to automatically return a new BadRequestObjectResult(actionContext.ModelState) - since in case of binding error with a NULL bound value there's nothing to do and in case of validation errors we probably can't do anything either.

    Quick notes for the ApiBehaviorOptions:

    • must use ApiController attribute (which requires also routing attribute on the controller level also and does alter the way binding works)
    • the default behaviour with ApiController attribute will return a BadRequestObjectResult(actionContext.ModelState) without any extra code and configuration
    • if you decide to roll your own ApiBehaviorOptions - you must initialize it after service.AddMvc or need to use: services.PostConfigure(o => {}) which has similar effect
    • ApiBehaviorOptions SuppressModelStateInvalidFilter has to be false for the InvalidModelStateResponseFactory to work

    So in some cases a custom filter is a better solution (less changes).

    0 讨论(0)
  • 2020-12-19 17:45

    Add attribute below in your project

    public class ValidateModelAttribute : ActionFilterAttribute
    {
        public override void OnActionExecuting(ActionExecutingContext context)
        {
            base.OnActionExecuting(context);
    
            if (!context.ModelState.IsValid)
                context.Result = new BadRequestObjectResult(new
                {
                    message = context.ModelState.Values.SelectMany(v => v.Errors.Select(e => e.ErrorMessage))
                });
        }
    }
    

    Change your api like this

    [HttpPut("{id}")]
    [ValidateModel]
    public async Task<IActionResult> UpdateAsync(
        [FromRoute] int id,
        [FromBody] ThingModel model)
    

    id contains a non-digit => 400

    model does not pass annotation validation inside => 400

    if you want to reject unacceptable values in model with 422 code, implement in your controller

    0 讨论(0)
提交回复
热议问题