1
votes

I'm using WebAPI 2.2, attribute based routing and I can't seem to figure out why query strings aren't working or how to enable them. I have read other SO questions regarding this, but they didn't quite apply to me.

Here's a really simple APIController:

[Route("api/HelloMessage")]
public async Task<IHttpActionResult> Get()
{
    var result = await Task.FromResult(new string[] { "Hello", "World" }).ConfigureAwait(false);
    return Ok(result);
}

[Route("api/HelloMessage/{id}")]
public async Task<IHttpActionResult> Get(int id)
{
    var result = await Task.FromResult($"Hello {id}").ConfigureAwait(false);
    return Ok(result);
}

(also, go to WebApiConfig.cs, and comment out the default route that is created with MapHttpRoute)

If I hit it with http://localhost/api/HelloMessage/1, it works great.

However, if I hit it with http://localhost/api/HelloMessage?id=1, it binds to the parameterless version. Where am I going wrong?

One weird thing:

If I re-enabled the MapHttpRoute code, then the routing works (so ?id=1 routes to the parameterized method).

I woudl like to know why this doesn't work with Attribute based routing though. Is this a bug, or am I just doing it wrong?

here's the MapHttpRoute code that will make it work:

    config.Routes.MapHttpRoute(
        name: "DefaultApi",
        routeTemplate: "api/{controller}/{id}",
        defaults: new { id = RouteParameter.Optional }
    );
1

1 Answers

1
votes

That is by design. the default convention-based routing would map a route like api/{controller}/{id} to your parameter-less action because {id} is optional, as stated by defaults: new { id = RouteParameter.Optional }.

With attribute routing however you have more control and flexability over the routing process.

For example in attribute routing you can make id optional like this

[Route("api/HelloMessage/{id?}")]
public async Task<IHttpActionResult> Get(int id) {...}

But that would cause a conflict with the first route as now they both match api/HelloMessage.

If you want http://localhost/api/HelloMessage?id=1 to work by retrieving the id from the uri then you need to first remove the action that does not have the parameter or change it's route to make it distinct and make the other action's id optional.

The frame work will match the ?id=1 in the URI to the parameter and pass the value to the parameter.