Api Versioning – with header and with url

 

Untitled

WebApiConfig.cs

public static class WebApiConfig
{
public static void Register(HttpConfiguration config)
{
//// CODE IS FOR VERSIONING USING HEADER

config.MapHttpAttributeRoutes();
config.Routes.MapHttpRoute(
name: “DefaultApi”,
routeTemplate: “api/{controller}/{id}”,
defaults: new { id = RouteParameter.Optional }
);
config.Services.Replace(typeof(IHttpControllerSelector), new CustomControllerSelector((config)));

// //// CODE IS FOR VERSIONING USING URL

//var constraintsResolver = new DefaultInlineConstraintResolver();
//constraintsResolver.ConstraintMap.Add(“apiVersion1Constraint”, typeof(ApiVersion1Constraint));
//constraintsResolver.ConstraintMap.Add(“apiVersion2Constraint”, typeof(ApiVersion2Constraint));
//config.MapHttpAttributeRoutes(constraintsResolver);
//config.Services.Replace(typeof(IHttpControllerSelector), new NamespaceHttpControllerSelector(config));
}
}

V1/CustomerController.cs

namespace ApiVersion.Controllers.V1
{
[RoutePrefix(“api/{apiVersion1:apiVersion1Constraint(v1)}/customer”)]
public class CustomerController : ApiController
{
[Route(“”, Name = “GetCustomer1”)]
[HttpGet]
public Customer GetCust1()
{
return new Customer
{
CustomerId = 210,
Name = “Jack in V1”,
Address = “Uk”
};
}
}
}

V2/CustomerController.cs
namespace ApiVersion.Controllers.V2
{
[RoutePrefix(“api/{apiVersion2:apiVersion2Constraint(v2)}/customer”)]
public class CustomerController : ApiController
{
[Route(“”, Name = “GetCustomer2”)]
[HttpGet]
public Customer GetCust2()
{
return new Customer
{
CustomerId = 100,
Name = “Jack in V2”,
Address = “Pune”
};
}
}}

USING HEADER 

Add new class CustomControllerSelector.cs

public class CustomControllerSelector : DefaultHttpControllerSelector
{
private HttpConfiguration _config;
private readonly Lazy<Dictionary<string, HttpControllerDescriptor>> _controllers;
public CustomControllerSelector(HttpConfiguration config)
: base(config)
{
_config = config;
_controllers = new Lazy<Dictionary<string, HttpControllerDescriptor>>(InitializeControllerDictionary);

}

private Dictionary<string, HttpControllerDescriptor> InitializeControllerDictionary()
{
var dictionary = new Dictionary<string, HttpControllerDescriptor>(StringComparer.OrdinalIgnoreCase);
var assembliesResolver = _config.Services.GetAssembliesResolver();
var controllersResolver = _config.Services.GetHttpControllerTypeResolver();
var controllerTypes = controllersResolver.GetControllerTypes(assembliesResolver);
foreach (var controllerType in controllerTypes)
{
var segments = controllerType.Namespace.Split(Type.Delimiter);
var controllerName = controllerType.Name.Remove(controllerType.Name.Length – DefaultHttpControllerSelector.ControllerSuffix.Length);
var controllerKey = String.Format(CultureInfo.InvariantCulture, “{0}.{1}”,
segments[segments.Length – 1], controllerName);
if (!dictionary.Keys.Contains(controllerKey))
{
dictionary[controllerKey] = new HttpControllerDescriptor(_config,
controllerType.Name,
controllerType);
}
}
return dictionary;
}
public override HttpControllerDescriptor SelectController(HttpRequestMessage request)
{
var version = GetVersionFromAcceptHeaderVersion(request);

var _route = request.GetRouteData();

var controllerName = base.GetControllerName(request);

var controllerKey = String.Format(CultureInfo.InvariantCulture, “V{0}.{1}”,
version, controllerName);
var type = _config.Services.GetAssembliesResolver();
var controlles = _config.Services.GetHttpControllerTypeResolver().GetControllerTypes(type);

HttpControllerDescriptor controllerDescriptor;
if (_controllers.Value.TryGetValue(controllerKey, out controllerDescriptor))
{
return controllerDescriptor;
}

throw new HttpResponseException(HttpStatusCode.NotFound);

}

private string GetVersionFromAcceptHeaderVersion(HttpRequestMessage request)
{
var acceptHeader = request.Headers.Accept;
foreach (var mime in acceptHeader)
{
if (mime.MediaType == “application/json” || mime.MediaType == “text/html”)
{
var version = mime.Parameters
.Where(v => v.Name.Equals(“version”, StringComparison.OrdinalIgnoreCase))
.FirstOrDefault();
if (version != null)
{
return version.Value;
}
return string.Empty;
}
}
return string.Empty;
}

}

USING URL
Add new class VersionConstraint.cs  and NamespaceHttpControllerSelector.cs

In VersionConstraint.cs

public class ApiVersion1Constraint : IHttpRouteConstraint
{
public ApiVersion1Constraint(string allowedVersion)
{
AllowedVersion = allowedVersion.ToLowerInvariant();
}
public string AllowedVersion { get; private set; }
//Matching the version from requested route
public bool Match(HttpRequestMessage request, IHttpRoute route, string parameterName,
IDictionary<string, object> values, HttpRouteDirection routeDirection)
{
object value;
if (values.TryGetValue(parameterName, out value) && value != null)
{
return AllowedVersion.Equals(value.ToString().ToLowerInvariant());
}
return false;
}
}
public class ApiVersion2Constraint : IHttpRouteConstraint
{
public ApiVersion2Constraint(string allowedVersion)
{
AllowedVersion2 = allowedVersion.ToLowerInvariant();
}
public string AllowedVersion2 { get; private set; }
//Matching the version from requested route
public bool Match(HttpRequestMessage request, IHttpRoute route, string parameterName,
IDictionary<string, object> values, HttpRouteDirection routeDirection)
{
object value;
if (values.TryGetValue(parameterName, out value) && value != null)
{
return AllowedVersion2.Equals(value.ToString().ToLowerInvariant());
}
return false;
}
}

In NamespaceHttpControllerSelector.cs

public class NamespaceHttpControllerSelector : IHttpControllerSelector
{
private readonly HttpConfiguration _configuration;
private readonly Lazy<Dictionary<string, HttpControllerDescriptor>> _controllers;
public NamespaceHttpControllerSelector(HttpConfiguration config)
{
_configuration = config;
_controllers = new Lazy<Dictionary<string, HttpControllerDescriptor>>(InitializeControllerDictionary);
}
public HttpControllerDescriptor SelectController(HttpRequestMessage request)

{
var routeData = request.GetRouteData();
if (routeData == null)
{
throw new HttpResponseException(HttpStatusCode.NotFound);
}
var controllerName = GetControllerName(routeData);
if (controllerName == null)
{
throw new HttpResponseException(HttpStatusCode.NotFound);
}
var namespaceName = GetVersion(routeData);
if (namespaceName == null)
{
throw new HttpResponseException(HttpStatusCode.NotFound);
}
var controllerKey = String.Format(CultureInfo.InvariantCulture, “{0}.{1}”,
namespaceName, controllerName);

HttpControllerDescriptor controllerDescriptor;
if (_controllers.Value.TryGetValue(controllerKey, out controllerDescriptor))
{
return controllerDescriptor;
}
throw new HttpResponseException(HttpStatusCode.NotFound);
}
public IDictionary<string, HttpControllerDescriptor> GetControllerMapping()
{
return _controllers.Value;
}
private Dictionary<string, HttpControllerDescriptor> InitializeControllerDictionary()
{
var dictionary = new Dictionary<string, HttpControllerDescriptor>(StringComparer.OrdinalIgnoreCase);
var assembliesResolver = _configuration.Services.GetAssembliesResolver();
var controllersResolver = _configuration.Services.GetHttpControllerTypeResolver();
var controllerTypes = controllersResolver.GetControllerTypes(assembliesResolver);
foreach (var controllerType in controllerTypes)
{
var segments = controllerType.Namespace.Split(Type.Delimiter);
var controllerName = controllerType.Name.Remove(controllerType.Name.Length – DefaultHttpControllerSelector.ControllerSuffix.Length);
var controllerKey = String.Format(CultureInfo.InvariantCulture, “{0}.{1}”,
segments[segments.Length – 1], controllerName);
if (!dictionary.Keys.Contains(controllerKey))
{
dictionary[controllerKey] = new HttpControllerDescriptor(_configuration,
controllerType.Name,
controllerType);
}
}
return dictionary;
}
private static T GetRouteVariable<T>(IHttpRouteData routeData, IEnumerable<string> names)
{
object result;

foreach (var name in names)
{
if (routeData.Values.TryGetValue(name, out result))
{
return (T)result;
}
}
return default(T);
}

private string GetControllerName(IHttpRouteData routeData)
{
var subroute = routeData.GetSubRoutes().FirstOrDefault();
if (subroute == null) return null;
var actions = subroute.Route.DataTokens[“actions”] as HttpActionDescriptor[];
string controllerName = string.Empty;
if (actions != null && actions.Length > 0)
{
controllerName = actions[0].ControllerDescriptor.ControllerName.Replace(“Controller”,string.Empty);
}

return controllerName;
}

private string GetVersion(IHttpRouteData routeData)
{
var subRouteData = routeData.GetSubRoutes().FirstOrDefault();
if (subRouteData == null) return null;
var routevariable = GetRouteVariable<string>(subRouteData, versionnumber);
return routevariable;
}

private List<string> versionnumber = new List<string>()
{
“apiVersion1” ,
“apiVersion2”
};
}

Done!

Request call like

Header- 

http://localhost:58892/api/customer

in Header accept : application/json;version=2

By Url

http://localhost:58892/api/v1/customer

http://localhost:58892/api/v2/customer

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s