Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Inconsistent behaviour with ModelState validation asp.net core api

I get an inconsistent behaviour when asp.net core api validates objects and when I manually add model errors and invoke BadRequest(ModelState)

As an example, I have these 2 endpoints in my controller

[HttpPost]
public IActionResult Post(MyModel model)
{
    return Ok();
}

[HttpPost]
[Route("test")]
public IActionResult OtherPost()
{
    ModelState.AddModelError("field", "error");
    return BadRequest(ModelState);
}

and MyModel is:

public class MyModel
{
    [Required]
    [MinLength(10)]
    public string MyProperty { get; set; }
}

When I invoke the first endpoint with an empty body I don't need to validate ModelState because the framework is going to do it automatically and gives this response:

{
"errors":{"MyProperty":["The MyProperty field is required."]},
"title":"One or more validation errors occurred.",
"status":400,
"traceId":"80000005-0000-ff00-b63f-84710c7967bb"
}

With the second controller I get this:

{"field":["error"]}

Am I using the wrong method to add errors to ModelState or it is an known problem?

like image 502
nicecatch Avatar asked Mar 21 '19 21:03

nicecatch


1 Answers

  1. If you prefer to validating the model state by yourself and expect a exactly same result as the failure message of ApiController binding, you could make it as below :
    public IActionResult Other2Post()
    {
        ModelState.AddModelError("field", "error");
        var problemDetails = new ValidationProblemDetails(ModelState)
        {
            Status = StatusCodes.Status400BadRequest,
        };

        var traceId = Activity.Current?.Id ?? HttpContext.TraceIdentifier;
        problemDetails.Extensions["traceId"] = traceId;

        var result = new BadRequestObjectResult(problemDetails);
        result.ContentTypes.Add("application/problem+json");
        result.ContentTypes.Add("application/problem+xml");
        return result;
    }
  1. Or if you don't need the traceId, you could simply return a BadRequest of ValidationProblemDetails:
    ModelState.AddModelError("field", "error");
    var problemDetails = new ValidationProblemDetails(ModelState)
    {
        Status = StatusCodes.Status400BadRequest,
    };
    return BadRequest(problemDetails);

Demo :

enter image description here

For more information, see the related source code here and here.

like image 143
itminus Avatar answered Sep 21 '22 07:09

itminus