Skip to content

How to Version Your Service

Chris Martinez edited this page Sep 14, 2016 · 11 revisions

REST services are implemented in ASP.NET as a controller. To version your service, you simply need to decorate your controller with the appropriate API version information.

How It Works

API versioning does not have a direct influence on routing. The way that you create and define routes remains unchanged. The key difference is that routes may now overlap depending on whether you are using convention-based routing, attribute-based routing, or both. In the case of attribute routing, multiple controllers will define the same route. The default services in each flavor of ASP.NET assumes a one-to-one mapping between routes and controllers and, therefore, considers duplicate routes to be ambiguous. The API versioning services replace the default implementations and allow controllers to also be disambiguated by API version. Although multiple routes may match a request, they are expected to be distinguishable by API version. If the routes cannot be disambiguated, this is likely a developer mistake and the behavior is the same as the default implementation.

Supported Routing Methods

The following table outlines the various supported routing methods:

Routing Method Supported
Attribute-based routing Yes
Convention-based routing Yes
Attribute and convention-based routing (mixed) Yes

Convention-based routing is normally defined by inferring the route from the name of the controller type without the Controller suffix. For example, HelloWorldController is interpreted as the HelloWorld route. Unfortunately, this causes an issue for service API versioning if you want split the implementation across different types. To address this issue, you can decorate convention-based controllers that are versioned into different types using the ControllerNameAttribute. In the strictest sense, this is not a convention, but this is only way to make a new controller type match an existing convention-based route with an API version. For example:

[ApiVersion( "2.0" )]
[ControllerName( "HelloWorld" )]
public class HelloWorld2Controller : Controller
{
    public string Get() => "Hello world v2.0!";
}

This approach is not required if you split the controller types into separate namespaces. For example:

namespace My.Services.V1
{
    [ApiVersion( "1.0" )]
    public class HelloWorldController : Controller
    {
        public string Get() => "Hello world v1.0!";
    }
}
namespace My.Services.V2
{
    [ApiVersion( "2.0" )]
    public class HelloWorldController : Controller
    {
        public string Get() => "Hello world v2.0!";
    }
}
Clone this wiki locally