8

Given following API

public class PagedRequest
{
  [Required, Range(1, 100, ErrorMessage = "Limit must be from 1 to 100.")]
  public int Top { get; set; }

  [Required, Range(0, int.MaxValue, ErrorMessage = "Skip must be 0 or greater.")]
  public int Skip { get; set; }
}

[Route("test")]
[HttpGet]
public ActionResult<BarResponse> GetFoos([FromQuery] PagedRequest request)
{
  if (!ModelState.IsValid) return BadRequest(ModelState);

  // Return 200 OK with data here
}

Works as expected:

  • test?skip=0&top=10 -> returns 200
  • test?skip=0&top=0 -> returns BadRequest with error messages

Doesn't work as expected

  • test?top=0, returns 200 OK, expected required field validation error for Skip field.

Notes:

  • Using ASP.NET Core 3.0
  • This used to work with FromUri in ASP.NET Framework 4.x, then I'ld use a non-parameterless constructor, which is no longer allowed
3
  • 2
    You could also use [BindRequired] instead. Commented Nov 20, 2019 at 14:44
  • Thanks @KirkLarkin. Using [BindRequired] makes it work without changing to nullable ints. If you want to add that as an answer I'll mark it as the accepted answer. Commented Nov 20, 2019 at 14:52
  • 2
    @KirkLarkin is correct. Here is a link to docs to support the provided suggestion learn.microsoft.com/en-us/aspnet/core/mvc/models/… Commented Nov 20, 2019 at 15:04

2 Answers 2

5

You can replace the [Required] attribute with the [BindRequired] attribute, which:

Causes model binding to add a model state error if binding cannot occur for a model's property.

public class PagedRequest
{
    [BindRequired, Range(1, 100, ErrorMessage = "Limit must be from 1 to 100.")]
    public int Top { get; set; }

    [BindRequired, Range(0, int.MaxValue, ErrorMessage = "Skip must be 0 or greater.")]
    public int Skip { get; set; }
}
Sign up to request clarification or add additional context in comments.

Comments

1

It's likely you're missing the ApiController attribute on your Controller class. This attribute applies a couple of default conventions which are common for web APIs, but uncommon for web pages. Although honestly I can't really figure out which convention it is that makes your sample work. It probably has something to do with the model binder.

See: https://learn.microsoft.com/en-us/aspnet/core/web-api/?view=aspnetcore-3.0#apicontroller-attribute

Additionally, with the ApiController attribute you no longer need to check to model state yourself. If the model state is invalid, ASP.NET Core MVC will automatically return a bad request response. So you can remove this part after applying the attribute:

if (!ModelState.IsValid) return BadRequest(ModelState);

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.