2

I have two Controllers as follows:

[RoutePrefix("v1/user/something")]
public class SomethingsController : ApiController
{
    [Route("{id}")]
    [HttpGet]
    [ResponseType(typeof(SomethingsViewModel))]
    public async Task<IHttpActionResult> GetAsync([FromUri]int id)
    {
    }
}

[RoutePrefix("v1/user")]
public class UserController : ApiController
{
    [Route("{id}")]
    [HttpGet]
    [Authorize(Roles = "Super Admin")]
    public async Task<IHttpActionResult> GetByIdAsync([FromUri]int id)
    {
    }
}

Now by looking at the code above, I'd think that the following two routes are being created:

  • v1/user/something/{id}
  • v1/user/{id}

But unfortunately, for some reason, that is not the case. I keep getting the following exception message when trying to access one of the above routes:

Multiple controller types were found that match the URL. This can happen if attribute routes on multiple controllers match the requested URL. The request has found the following matching controller types: MyProject.Api.Controllers.UserController, MyProject.Api.Controllers.SomethingsController

Please help me out in figuring what I might be doing wrong or which small detail am I missing out here.

Nkosi
  • 235,767
  • 35
  • 427
  • 472
Haseeb Ahmed
  • 643
  • 5
  • 16
  • In case of Attribute routing, Web API tries to find all the controllers which match a request. If it sees that multiple controllers are able to handle this, then it throws an exception – Divyang Desai Sep 20 '16 at 10:33
  • @Div I do know that but the issue is that if you look at the above code, multiple controllers shouldn't be able to handle it since there RoutePrefix are different. – Haseeb Ahmed Sep 20 '16 at 10:42
  • @haseebahmed7 though their route prefix are different their resolved routes match. for example `v1/user/{id}` with match `v1/user/something/{id}` where id parameter arg in the first route will take `something/{id}`. Route prefix and Route attributes combine to create a full route that is added to the route table. – Nkosi Sep 20 '16 at 11:16
  • Possible duplicate of: http://stackoverflow.com/questions/23094584/multiple-controller-types-with-same-route-prefix-asp-net-web-api – Marcus Höglund Sep 20 '16 at 11:22

1 Answers1

3

Though their route prefix are different their resolved routes match. for example v1/user/{id} will match v1/user/something/{id} where id parameter arg in the first route will take something/{id}.

Route prefix and Route attributes combine to create a full route that is added to the route table.

In a case like this you will need to use constraints in order to better differentiate the routes.

[RoutePrefix("v1/user/something")]
public class SomethingsController : ApiController {
    [Route("{id:int}")]
    [HttpGet]
    [ResponseType(typeof(SomethingsViewModel))]
    public async Task<IHttpActionResult> GetAsync([FromUri]int id) { ... }
}

[RoutePrefix("v1/user")]
public class UserController : ApiController {
    [Route("{id:int}")]
    [HttpGet]
    [Authorize(Roles = "Super Admin")]
    public async Task<IHttpActionResult> GetByIdAsync([FromUri]int id) { ... }
}

So now with the int constraint something wont be mistaken for valid parameter for the UserController.GetByIdAsync action

Reference Attribute Routing in ASP.NET Web API 2: Route Constraints

Route Constraints

Route constraints let you restrict how the parameters in the route template are matched. The general syntax is "{parameter:constraint}". For example:

[Route("users/{id:int}"]
public User GetUserById(int id) { ... }

[Route("users/{name}"]
public User GetUserByName(string name) { ... }

Here, the first route will only be selected if the "id" segment of the URI is an integer. Otherwise, the second route will be chosen.

Nkosi
  • 235,767
  • 35
  • 427
  • 472