0

I have an Account controller with two Get methods, one that gets all accounts and takes no input, and another that takes an Id int and returns that specific account.

The project constraints are that we can't have id as an optional parameter on the default route, but instead need get-one-account and get-all-accounts to be accessed via different routes, and we can't use attribute routing. So our route configuration currently looks like this:

config.Routes.MapHttpRoute("AccountWithId", "api/account/{id}", new { action = "Get", id = RouteParameter.Optional }
                , new { httpMethod = new HttpMethodConstraint(HttpMethod.Get), id = @"\d+" });

config.Routes.MapHttpRoute("Default", "api/{controller}");

My two Get methods on the AccountController look like this:

public IHttpActionResult Get()
        {
            IList<AccountDto> users = m_service.Get();

            return Ok(users);
        }

        public IHttpActionResult Get(int accountId)
        {
            AccountDto user = m_service.Get(accountId);

            return Ok(user);
        }

But when I call Get with an id parameter in my test via my custom route and debug as below, it's still hitting the Get method that doesn't take an id parameter and returns all.

var url = "http://test/api/account/" + accountId;

var response = await m_server.HttpClient.GetAsync(url);

Any idea why?

RSid
  • 768
  • 1
  • 8
  • 30
  • If **accountId** is optional, **Get(int accountId)** will be hidden by overload **Get()**. So you cannot make **accountId** optional. – Win Dec 11 '14 at 19:32
  • Its obvious that when a value is optional it always hits the same route becoz if supplied or not its optional hence no issue that route will always be the prior and will be hidden by the overload get – Tushar Gupta Dec 11 '14 at 19:38
  • @Win Makes sense, but there's not a RouteParameter.Required option, and it fails in the exact same way with that parameter removed. I was following the advice in this question: http://stackoverflow.com/questions/9499794/single-controller-with-multiple-get-methods-in-asp-net-web-api – RSid Dec 11 '14 at 19:40

1 Answers1

2

There are a number of problems I can see here.

Your first route does not specify a default controller and I'm surprised you didn't get a 404 when sending an accountid.

Secondly if the id parameter is optional the regex should be \d* not \d+.

Thirdly the parameter names in your actions should match your routing parameters, so accountId should be changed to id.

Try this for your routing:

config.Routes.MapHttpRoute("AccountWithId",
    "api/account/{id}",
    new { controller = "Account", action = "Get", id = RouteParameter.Optional },
    new { httpMethod = new HttpMethodConstraint(HttpMethod.Get), id = @"\d*" }
);

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

and then change your action signatures to:

public IHttpActionResult Get()
{
    ...
}

public IHttpActionResult Get(int id)
{
    ...
}
Jon Susiak
  • 4,948
  • 1
  • 30
  • 38
  • Good catch on the parameter name and regex, thanks. I should have added to the question that I did try specifying the Account controller, though, and it didn't solve the problem. Is there no way to make this work without having '/{id}' on the default route at all? – RSid Dec 12 '14 at 14:05
  • Yes, if you want to remove the {id} parameter on the default route (defaultapi) it should still work for the cases you have shown above. I've tested this out and it routes correctly so if you are still having problems there must be some info we're missing. – Jon Susiak Dec 12 '14 at 14:13