Take the 2-minute tour ×
Stack Overflow is a question and answer site for professional and enthusiast programmers. It's 100% free, no registration required.

I am reading about Attribute Routing in Web API 2 from here

The article says,

Here are some other patterns that attribute routing makes easy.

API versioning

In this example, “/api/v1/products” would be routed to a different controller than “/api/v2/products”.

/api/v1/products
/api/v2/products

How come?

EDIT: I would do this in Normal Routing:

public static class WebApiConfig
{
    public static void Register(HttpConfiguration config)
    {
         config.Routes.MapHttpRoute(
            name: "DefaultApi",
            routeTemplate: "api/v2/products",
            defaults: new { controller = V2_Products }
        );

        config.Routes.MapHttpRoute(
            name: "DefaultApi",
            routeTemplate: "api/v1/products",
            defaults: new { controller = V1_Products }
        );
    }
}

Could anyone explain me how to do this in Attribute Routing way ? And how come using Attribute routing is easier and convenient for this example (according to the article) ?

share|improve this question
add comment

3 Answers

up vote 2 down vote accepted

There are many ways to implement versionning with attribute routing ; A really basic way is to use RoutePrefix attribute for each version of your ApiController

[RoutePrefix("v1")]
public class V1_ProductsController : ApiController
{
    [Route("products")]
    public IEnumerable<string> Get()
    {
        return new string[] { "v1-product1", "v1-product2" };
    }
     //....
}


[RoutePrefix("v2")]
public class V2_ProductsController : ApiController
{
     [Route("products")]
    public IEnumerable<string> Get()
    {
        return new string[] { "v2-product1", "v2-product2" };
    }
    //....
}

/v1/products goes to the first version of /v2/products goes to the second one.

share|improve this answer
add comment

Another simple way is configuring your route as api/{folder}/{controller}/{action} where in to folder you can give name as V1 or V2.

A good way can be implementing your own Controller selector. You can use this link for more information.

The interface that Web API uses to select a controller is IHttpControllerSelector. The important method on this interface is SelectController, which selects a controller for a given HttpRequestMessage.

share|improve this answer
add comment

You can do it by overriding DefaultHttpControllerSelector

there you override method to selectcontroller

public override HttpControllerDescriptor SelectController(HttpRequestMessage request)
            {
                HttpControllerDescriptor controllerDescriptor = null;
                IDictionary<string, HttpControllerDescriptor> controllers = GetControllerMapping();

                IHttpRouteData routeData = request.GetRouteData();

                if (routeData == null)
                {
                    throw new HttpResponseException(HttpStatusCode.NotFound);
                }

                object apiVersion;
                if (!routeData.Values.TryGetValue("Version", out apiVersion))
                {
                    apiVersion = "1";
                }


                object controllerName;
                if (!routeData.Values.TryGetValue("controller", out controllerName))
                {
                    controllerName = string.Empty;
                }
                if (controllerName == null)
                {
                    throw new HttpResponseException(HttpStatusCode.NotFound);
                }

                string newControllerName = String.Concat(controllerName.ToString(), "V", apiVersion);

                if (controllers.TryGetValue(newControllerName, out controllerDescriptor))
                {
                    return controllerDescriptor;
                }
                if (controllers.TryGetValue(controllerName.ToString(), out controllerDescriptor))
                {
                    return controllerDescriptor;
                }
                throw new HttpResponseException(HttpStatusCode.NotFound);

            }

Then you are adding routes webapiconfig

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

and register controller selector in webapiconfig

config.Services.Replace(typeof(IHttpControllerSelector), new ApiVersioningSelector(config));

So from now if you name controller ProductsV1Controller it will reffer /api/v1/products. Also please note that my example also support routes without version so if v1 is not found it will try to check if ProductsController exists

PS. Code is update one bug was there :(

share|improve this answer
add comment

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.