Omkar
Omkar

Reputation: 2149

Adding constraint with HttpGet (...) does not work in ASP.Net Core

I am newbie to ASP.NET core platform. I am working on sample application where I am pooling some daily data from service. My API signature as below -

[HttpGet("daily/{state}/{year}/{month}/{day}")]
public async Task<IActionResult> Daily([FromRoute] string state, [FromRoute] int year, [FromRoute] int month, [FromRoute] int day)
{
    //...
}

My requirement is to restrict state parameter to 3 characters and all caps.

So I did this -

[HttpGet("daily/{state:regex(A-Z):maxlength(3)}/{year}/{month}/{day}")]
public async Task<IActionResult> Daily([FromRoute] string state, [FromRoute] int year, [FromRoute] int month, [FromRoute] int day)
{
    //...
}

If I add these constraints on route, I am getting page not found error.

It works fine if I put no constraint.

Updated - See following screen-shot from VS2017. I am passing URL like http://localhost:51208/api/daily/mah/2018/08/13 and still ModelState's IsValid returns true. Why?

enter image description here

Upvotes: 1

Views: 2266

Answers (2)

Nkosi
Nkosi

Reputation: 247133

Not found is because the URL being called most likely does not match the regex constraint.

Consider checking your regular expression.

Simple example

^[A-Z]{1,3}$

Matches a single character in the range: [A-Z] between 1 and 3 times.

That means it will match from A to ZZZ

If the length must be exactly 3 characters then remove the range

^[A-Z]{3}$

Which will match AAA to ZZZ

So update the constraint accordingly.

[HttpGet("daily/{state:regex(^[[A-Z]]{{3}}$)}/{year:int}/{month:int}/{day:int}")]

Note that Regular expression tokens must be escaped. For example, \,{,},[,] characters need to be escaped by doubling them to escape the Routing parameter delimiter characters.

Reference Routing in ASP.NET Core: Regular expressions about escaping the regular expression.

For the desired match

GET {host}/daily/ABC/2019/01/20

Upvotes: 2

Amir
Amir

Reputation: 2022

What you can do is in a more cleaner way is make a model for your get request.

  public class DailyModel
    {
        [Required]
        [RegularExpression("^[A-Z]{3}$", ErrorMessage ="State should be length of 3 and all in Upper Case")]
        public string State { get; set; }
        public int Year { get; set; }
        public int Month { get; set; }
        public int Day { get; set; }
    }

And apply data annotation to your fields like the above code. And on your controller, you can send the model state invalid message if the request is not valid.

  [Route("api/[controller]")]
    public class TestController : Controller
    {

        [HttpGet("daily/{state}/{year}/{month}/{day}")]
        public async Task<IActionResult> Daily([FromRoute] DailyModel model)
        {
            if (!ModelState.IsValid)
            {
                return BadRequest(ModelState);
            }

          ...
        }
    }

Upvotes: 3

Related Questions