3

I have an ASP.NET Web API 2 application which uses convention-based routing:

[app-url]/v1/[controller]

Now, I want to add another version to the API, and found that attribute routing is the easiest way to achieve what I want. Therefore, I registered the Web API routes in the Application_Start() method as shown below.

GlobalConfiguration.Configure(WebApiConfig.Register);

Additionally, I made sure that the Register() method in the WebApiConfig class only contains the following line:

config.MapHttpAttributeRoutes();

There are two controllers to test the versioning:

/v1/StatusController.cs

[RoutePrefix("v1/status")]
public class StatusController : ApiController
{
    [Route("")]
    public string Get()
    {
        return "V1 - OK";
    }
}

/v2/StatusController.cs

[RoutePrefix("v2/status")]
public class StatusController : ApiController
{
    [Route("")]
    public string Get()
    {
        return "V2 - OK";
    }
}

However, when I navigate to either of the routes shown below, I receive an error.

  1. [app-url]/v1/status
  2. [app-url]/v2/status

SERVER ERROR

404 - File or directory not found.

The resource you are looking for might have been removed, had its name changed, or is temporarily unavailable.

prd
  • 2,272
  • 2
  • 17
  • 32
Fusyoo
  • 39
  • 2
  • 8
  • 1
    How do you have two classes with the same name in your project? – DavidG Feb 13 '19 at 10:51
  • 1
    They are under different namespaces. (Controllers.V1 and Controllers.V2) – Fusyoo Feb 13 '19 at 10:52
  • 1
    Which URL do you access? – Markus Feb 13 '19 at 10:53
  • Oops, I forgot to mention that. Edited the question. – Fusyoo Feb 13 '19 at 10:54
  • 2
    Rather than rely on manual routing, I would suggest you look at the Microsoft API versioning Nuget package. It is built to allow you to specify versions and is quite simple to use. – DavidG Feb 13 '19 at 10:55
  • 1
    I tried that package, and I managed to get the versioning to work without too much work, and for this, I thank you. But, this is only __a__ solution for the problem, not __the__ solution for the attribute routing not working. – Fusyoo Feb 13 '19 at 11:25

2 Answers2

2

Your approach will not work because ASP.NET Web API uses a so-called Controller Selector to find the respective controller for a given route. This selector however, does not take into account the namespace of a controller, but rather uses its name.

By default, Web API ships with the DefaultHttpControllerSelector and you can find information on its implementation here.

A possible solution to your problem is to implement a custom IHttpControllerSelector and tell Web API to use it instead. For this you can find several examples on the internet.

Instead you can also change your controller names to be unique, e.g.:

  • StatusV1Controller
  • StatusV2Controller
prd
  • 2,272
  • 2
  • 17
  • 32
  • Changing the controller names would cause truble with applications already using the API, because (to my understanding) the URL to each endpoint would be different. In this case the best approach indeed would be implementing my own controller selector. – Fusyoo Feb 13 '19 at 12:30
  • For some reason I tought that the controller's name must be the same as the one's controller referenced in the URL. I'm relatively new to ASP.NET so some areas still cause some confusion. Thank you for clarifying this. – Fusyoo Feb 13 '19 at 12:42
2

Instead of using different namespaces, use different controller names (if this works for you). If so, here is about how the code should look like:

/v1/StatusController.cs:

[System.Web.Http.RoutePrefix("v1/status")]
public class StatusController : ApiController
{
    [System.Web.Http.Route("")]
    public string Get()
    {
        return "V1 - OK";
    }
 }

/v2/StatusController.cs:

[System.Web.Http.RoutePrefix("v2/status")]
public class Status2Controller : ApiController
{
    [System.Web.Http.Route("")]
    public string Get()
    {
        return "V2 - OK";
    }
 }

Now you would be able to invoke these 2 different versions by calling the Http Get Method like:

Https://YourUrl.com/v1/status

and:

Https://YourUrl.com/v2/status

Hope this suggested alternative helps. Good luck.

James Lee
  • 754
  • 8
  • 13
  • The only problem with this solution is that it would change the URL to the endpoint, and that would break applications already using the API. (please correct me if I'm wrong) – Fusyoo Feb 13 '19 at 12:32
  • The endpoints would be reached entirely by the defined route, so you would be ok in that case as well. For example: [System.Web.Http.Route("{id:int}")] would be reached by using using the Http Get Method with Https://YourUrl.com/v2/status/2. Looks like my example request Urls above didn't make it, so I'll see if I can edit my original answer to include that info as well. Does this answer your question? – James Lee Feb 13 '19 at 13:00
  • So just to add to my prior comment to provide clarification, is your request Url was Https://YourUrl.com/v1/status/2, that would go to the "StatusController", whereas in the prior comment, that request Url of Https://YourUrl.com/v2/status/2 would go to the "Status2Controller". Hope this comment clarifies any potential confusion. Let me know. – James Lee Feb 13 '19 at 13:17