I have the following API controller class.
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Routing;
namespace Core31Test.Controllers
{
[ApiController]
[Route("[controller]")]
public class DataController : ControllerBase
{
[HttpGet]
[Route("query/{idr:int?}")]
public string Get(int idr, [FromQuery] int id)
{
var idx = id == 0 ? idr : id;
return $"Value: {idx}";
}
[HttpGet]
[Route("query/{cityr}")]
public string GetByCity(string cityr, [FromQuery] string city)
{
var cityx = string.IsNullOrEmpty(city) ? cityr : city;
return cityx;
}
}
}
When I attempt to query by an id, both the route based path and the query string work. When I attempt to query by city, only the route based path works. The querystring path ends up taking the incorrect path.
For example:
http://localhost:51123/data/query/1
Result: value: 1
http://localhost:51123/data/query?id=1
Result: value: 1
http://localhost:51123/data/query/mycity
Result: mycity
http://localhost:51123/data/query?city=acity
Result: value: 0
In the last case, the incorrect route is being selected. Why is this happening and how can I fix it?
Edit 1
If I modify the route for the GetByCity method to be the one given below, the Get method is still selected. In this case, both methods have an optional route parameter and a querystring. Since the Get route specifies the input is an integer, I do not understand why the GetByCity method is going to that one. What I would like to know is how to make this work.
[Route("query/{cityr?}")]
{cityr}
part is not optional. So when you sendhttp://localhost:51123/data/query?city=acity
, that part{cityr}
is missing and that means it cannot match the methodGetByCity
. It instead matches the routequery/{idr:int?}
, theidr
is missing in the last case, the query?city
is not bound to any argument of the methodGet
. So bothid
&idr
are0
. – King Kingquery
is not taken into consideration for matching the route and find the action method. Query values don't always require the corresponding parameters (to be bound with) because the action code can get the query values easily via query value provider (accessed like a dictionary). You should not design your apis to be in such ambiguous selection. In the last case, which method is declared first (withRouteAttribute
) is more prioritized. You can try switching their declaration orders to see that.You can setOrder
(on[Route]
) explicitly but that's not really recommended. – King King