Chris Paton Chris Paton - 3 months ago 26
C# Question

Query string not working while using attribute routing

I'm using

System.Web.Http.RouteAttribute
and
System.Web.Http.RoutePrefixAttribute
to enable cleaner URLs for my Web API 2 application. For most of my requests, I can use routing (eg.
Controller/param1/param2
) or I can use query strings (eg.
Controller?param1=bob&param2=mary
).

Unfortunately, with one of my Controllers (and only one), this fails. Here is my Controller:

[RoutePrefix("1/Names")]
public class NamesController : ApiController
{

[HttpGet]
[Route("{name}/{sport}/{drink}")]
public List<int> Get(string name, string sport, string drink)
{
// Code removed...
}

[HttpGet]
[Route("{name}/{drink}")]
public List<int> Get(string name, string drink)
{
// Code removed...
}
}


When I make a request to either using routing, both work fine. However, if I use a query string, it fails, telling me that that path does not exist.

I have tried adding the following to my
WebApiConfig.cs
class'
Register(HttpConfiguration config)
function (before and after the Default route), but it did nothing:

config.Routes.MapHttpRoute(
name: "NameRoute",
routeTemplate: "{verId}/Names/{name}/{sport}/{drink}",
defaults: new { name = RouteParameter.Optional, sport = RouteParameter.Optional, drink = RouteParameter.Optional },
constraints: new { verId = @"\d+" });


So for clarity, I would like to be able to do both this:

localhost:12345/1/Names/Ted/rugby/coke
localhost:12345/1/Names/Ted/coke


and,

localhost:12345/1/Names?name=Ted&sport=rugby&drink=coke
localhost:12345/1/Names?name=Ted&drink=coke


but sadly the query string versions don't work! :(

Updated

I've removed the second Action altogether and now trying to use just a singular Action with optional parameters. I've changed my route attribute to
[Route("{name}/{drink}/{sport?}")]
as Tony suggested to make sport nullable, but this now prevents
localhost:12345/1/Names/Ted/coke
from being a valid route for some reason. Query strings are behaving the same way as before.

Update 2
I now have a singular action in my controller:

[RoutePrefix("1/Names")]
public class NamesController : ApiController
{

[HttpGet]
[Route("{name}/{drink}/{sport?}")]
public List<int> Get(string name, string drink, string sport = "")
{
// Code removed...
}
}


but still, using query strings does not find a suitable path, while using the routing method does.

Answer

After much painstaking fiddling and Googling, I've come up with a 'fix'. I don't know if this is ideal/best practice/plain old wrong, but it solves my issue.

All I did was add [Route("")] in addition to the route attributes I was already using. This basically allows Web API 2 routing to allow query strings, as this is now a valid Route.

An example would now be:

[HttpGet]
[Route("")]
[Route("{name}/{drink}/{sport?}")]
public List<int> Get(string name, string drink, string sport = "")
{
    // Code removed...
}

This makes both localhost:12345/1/Names/Ted/coke and localhost:12345/1/Names?name=Ted&drink=coke valid.

Comments