Шаг 1. Создайте класс ApiVersion1RoutePrefixAttribute.cs
public class ApiVersion1RoutePrefixAttribute: RoutePrefixAttribute {
private const string RouteBase = "api/{apiVersion:apiVersionConstraint(v1)}";
private const string PrefixRouteBase = RouteBase + "/";
public ApiVersion1RoutePrefixAttribute(string routePrefix):base (string.IsNullOrWhiteSpace(routePrefix)?RouteBase: PrefixRouteBase+routePrefix) {
}
}
Шаг 2. Создать класс ApiVersion2RoutePrefixAttribute.cs
public class ApiVersion1RoutePrefixAttribute: RoutePrefixAttribute {
private const string RouteBase = "api/{apiVersion:apiVersionConstraint(v1)}";
private const string PrefixRouteBase = RouteBase + "/";
public ApiVersion1RoutePrefixAttribute(string routePrefix):base (string.IsNullOrWhiteSpace(routePrefix)?RouteBase: PrefixRouteBase+routePrefix) {
}
}
Шаг 3. Создание класса ApiVersionConstraint
public class ApiVersionConstraint : IHttpRouteConstraint {
public string AllowedVersion { get; private set; }
public ApiVersionConstraint(string allowedVersion) {
this.AllowedVersion = allowedVersion.ToLowerInvariant();
}
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;
}
}
Шаг 4 Создайте класс 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 T GetRouteVariable<T>(IHttpRouteData routeData, string name) {
object result;
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;
//((HttpActionDescriptor[])subroute.Route.DataTokens["actions"]).First()
var dataTokenValue = subroute.Route.DataTokens["actions"];
if (dataTokenValue == null)
return null;
var controllerName = ((HttpActionDescriptor[])dataTokenValue).First().ControllerDescriptor.ControllerName.Replace("Controller", string.Empty);
return controllerName;
}
private string GetVersion(IHttpRouteData routeData) {
var subRouteData = routeData.GetSubRoutes().FirstOrDefault();
if (subRouteData == null) return null;
return GetRouteVariable<string>(subRouteData, "apiVersion");
}
}
шаг 5. Ваш файл WebApiConfig.cs должен выглядеть следующим образом
public static void Register(HttpConfiguration config) {
var constraintResolver = new DefaultInlineConstraintResolver();
constraintResolver.ConstraintMap.Add("apiVersionConstraint", typeof(ApiVersionConstraint));
config.MapHttpAttributeRoutes(constraintResolver);
config.Services.Replace(typeof(IHttpControllerSelector), new NamespaceHttpControllerSelector(config));
}
шаг 6. ваш контроллер должен выглядеть следующим образом
ваш контроллер версии 1
namespace AgentExperienceAPI.Controllers.v1 {
[Route("GetStatus")]
[AcceptVerbs("GET")]
public HttpResponseMessage GetStatus() {
return Request.CreateResponse(HttpStatusCode.OK, new Dictionary<string, object> {
{ "Status", "OK" }
});
}
}
ваш контроллер версии 2
namespace AgentExperienceAPI.Controllers.v1 {
[Route("GetStatus")]
[AcceptVerbs("GET")]
public HttpResponseMessage GetStatus() {
return Request.CreateResponse(HttpStatusCode.OK, new Dictionary<string, object> {
{ "Status", "OK" }
});
}
}
ваш контроллер должен находиться в двух отдельных папках, см. изображение
Swagger справится с остальными