Casey Crookston
Casey Crookston

Reputation: 13955

In .Net Core API, ModelState.IsValid is not catching Required parameters

.Net Core 3.1 API. I've read a lot of threads that ask about why ModelState.IsValid isn't working as expected. Most are for web pages and not API's. And the ones I have found about API's either don't exactly apply or didn't lead me to an understanding.

I have a model that looks like this:

public class MyModel
{
    [Required(ErrorMessage = "Prop1 is required.")]
    public int Prop1 { get; set; }

    public List<int> IntList { get; set; }
}

And I have an API endpoint:

[ApiController]
[Route("api/[controller]")]
public class FooBarController : ControllerBase
{
    [HttpPost]
    public async Task<IActionResult> Post([FromBody] MyModel request)
    {
        if (!ModelState.IsValid)
            return BadRequest(ModelState);

        // do stuff

        return Ok(results);

    }
}

Now, in Postman, if I pass this as the body, it works as expected:

{ "Prop1": 1001}

But if I pass this, I would expect an error of Prop1 is required. to be thrown:

{ "Prop2": 1001}

However, there is no error. The model is still valid and I just get back an empty set.

Upvotes: 1

Views: 1421

Answers (1)

Neil
Neil

Reputation: 11889

Integers have a default value of 0, therefore, once initialized, the value of prop1 will be 0, therefore it passes the [Required] test. If you make prop1 nullable, then required should catch if it is missing.

Or, if you don't want your property to be nullable, you can add a range validator:

[Required(ErrorMessage = "Prop1 is required.")]
[Range(1, int.MaxValue, ErrorMessage = "Prop1 must be greater than 0.")]
public int Prop1 { get; set; }

On a project last year, I created an attribute that was something like [NotNullOrDefault] which would work with integers being 0, or strings being null, or anything else not having it's default value.

Upvotes: 4

Related Questions