1

In my ASP.NET Core 2.0 application, I want to throw a 400 Bad Request when there is a syntax problem in the input (eg malformed json) and a 422 Unprocessable Entity for the other errors (eg Required, StringLength etc).

Is there a way to know (maybe looking into ModelState) if it a syntax (400) problem or a validation one (422)?

This is the controller action I am using...

    [HttpPost]
    public async Task<IActionResult> CreateArticle([FromBody] CreateArticleInput input)
    {
        if(!ModelState.IsValid)
        {
            // Return 400 or 422
        }
    }

4 Answers 4

2

When there is a syntax error/malformed payload the model binder won't populate the input parameter. Given this, you can check for input == null. When the requirements of the object are not met, ModelState.IsValid will return false and you can return a HTTP 422 accordingly.

Some example code:

public class MyObj
{
    [Required]
    public string Foo { get; set; }
}


[HttpPost]
public IActionResult Post([FromBody]MyObj obj)
{
    if (obj == null)
    {
        return BadRequest();
    }

    if (!ModelState.IsValid)
    {
        return UnprocessableEntity(ModelState);
    }

    return Ok();
}

When posting an invalid/malformed payload, obj will be null and a bad request (HTTP 400) will be returned. When the payload is correct JSON but the Foo property is null, ModelState.IsValid will return false which results in an HTTP 422 result with the validation binding errors. When all is well it will return a 200.

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

Comments

0

I am not quite sure what you are asking, sounds like the CreateArticleInput may be some sort of JSON input - but would have thought writing your own custom model binder would be the way to go. Then if the 'raw' input does not map correctly to your CreateArticleInput you can deal with it in whichever way you want. and possibly return the following from your modelbinder.

bindingContext.Result = ModelBindingResult.Failed();
return Task.CompletedTask;

and then

in the controller, if the CreateArticleInput input is null then return a 400 there..

https://learn.microsoft.com/en-us/aspnet/core/mvc/advanced/custom-model-binding?view=aspnetcore-2.1

Comments

0

Depending on what you are doing with it, you can get it from the HttpContext

return StatusCode(HttpContext.Response.StatusCode);

Comments

0

There is no way to mix-n-match return codes on a model binder level. Even 3rd party solutions, like FluentValidation, only allows you a single return pattern for a failed result.

As people suggested, add an additional syntax/semantic check on a controller level, and leave the input validation as is - much cleaner.

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.