public class WebApiControllerSelector : IHttpControllerSelector
{
private const string NamespaceKey = "namespace";
private const string ControllerKey = "controller"; private readonly HttpConfiguration _configuration;
private readonly Lazy<Dictionary<string, HttpControllerDescriptor>> _controllers;
private readonly HashSet<string> _duplicates; public WebApiControllerSelector(HttpConfiguration config)
{
_configuration = config;
_duplicates = new HashSet<string>(StringComparer.OrdinalIgnoreCase);
_controllers = new Lazy<Dictionary<string, HttpControllerDescriptor>>(InitializeControllerDictionary);
} private Dictionary<string, HttpControllerDescriptor> InitializeControllerDictionary()
{
var dictionary = new Dictionary<string, HttpControllerDescriptor>(StringComparer.OrdinalIgnoreCase); // Create a lookup table where key is "namespace.controller". The value of "namespace" is the last
// segment of the full namespace. For example:
// MyApplication.Controllers.V1.ProductsController => "V1.Products"
IAssembliesResolver assembliesResolver = _configuration.Services.GetAssembliesResolver();
IHttpControllerTypeResolver controllersResolver = _configuration.Services.GetHttpControllerTypeResolver(); ICollection<Type> controllerTypes = controllersResolver.GetControllerTypes(assembliesResolver); foreach (Type t in controllerTypes)
{
var segments = t.Namespace.Split(Type.Delimiter); // For the dictionary key, strip "Controller" from the end of the type name.
// This matches the behavior of DefaultHttpControllerSelector.
var controllerName = t.Name.Remove(t.Name.Length - DefaultHttpControllerSelector.ControllerSuffix.Length); var key = String.Format(CultureInfo.InvariantCulture, "{0}.{1}", segments[segments.Length - ], controllerName.ToLower()); // Check for duplicate keys.
if (dictionary.Keys.Contains(key))
{
_duplicates.Add(key);
}
else
{
dictionary[key] = new HttpControllerDescriptor(_configuration, t.Name, t);
}
} // Remove any duplicates from the dictionary, because these create ambiguous matches.
// For example, "Foo.V1.ProductsController" and "Bar.V1.ProductsController" both map to "v1.products".
foreach (string s in _duplicates)
{
dictionary.Remove(s);
}
return dictionary;
} // 取路由相应值
private static T GetRouteVariable<T>(IHttpRouteData routeData, string name)
{
object result = null;
if (routeData.Values.TryGetValue(name, out result))
{
return (T)result;
}
return default(T);
} //匹配相应路由
public HttpControllerDescriptor SelectController(HttpRequestMessage request)
{
IHttpRouteData routeData = request.GetRouteData();
if (routeData == null)
{
throw new HttpResponseException(HttpStatusCode.NotFound);
} //从Route中读取命名空间名称和控制器名称
string controllerName = GetRouteVariable<string>(routeData, ControllerKey).ToLower();
if (controllerName == null)
{
throw new HttpResponseException(HttpStatusCode.NotFound);
} HttpControllerDescriptor controllerDescriptor;
//获取版本号
var version = GetVersionFromAcceptHeaderVersion(request);
var versionedControllerName = string.Concat(controllerName, version).ToLower();
string versionkey = versionedControllerName;
//寻找匹配项
HttpControllerDescriptor versionedControllerDescriptor; //如果命名空间名称为空,调用BaseRoute,反之采用DefaultApi
string namespaceName = GetRouteVariable<string>(routeData, NamespaceKey);
string key = controllerName;
if (namespaceName != null)
{
key = String.Format(CultureInfo.InvariantCulture, "{0}.{1}", namespaceName, controllerName);
versionkey = String.Format(CultureInfo.InvariantCulture, "{0}.{1}", namespaceName, versionedControllerName);
if (_controllers.Value.TryGetValue(key, out controllerDescriptor))
{
if (_controllers.Value.TryGetValue(versionkey, out versionedControllerDescriptor))
{
return versionedControllerDescriptor;
} return controllerDescriptor;
}
else if (_duplicates.Contains(key))
{
throw new HttpResponseException(
request.CreateErrorResponse(HttpStatusCode.InternalServerError,
"该请求有多个控制器匹配,请检查路由配置"));
}
else
{
throw new HttpResponseException(HttpStatusCode.NotFound);
}
}
else
{
var basecontroller = _controllers.Value.Where(p => p.Key.ToLower().EndsWith(key));
if (basecontroller.Any())
{
if (basecontroller.Count() > )
{
throw new HttpResponseException(request.CreateErrorResponse(HttpStatusCode.InternalServerError,"该请求有多个控制器匹配,请检查路由配置"));
}
controllerDescriptor = basecontroller.FirstOrDefault().Value;
var baseVersioncontroller = _controllers.Value.Where(p => p.Key.ToLower().EndsWith(versionkey));
if (baseVersioncontroller.Any())
{
return baseVersioncontroller.FirstOrDefault().Value;
}
return controllerDescriptor;
}
else
{
throw new HttpResponseException(HttpStatusCode.NotFound);
}
}
} public IDictionary<string, HttpControllerDescriptor> GetControllerMapping()
{
return _controllers.Value;
} /// <summary>
/// 添加版本控制
/// </summary>
/// <param name="request"></param>
/// <returns></returns>
private string GetVersionFromAcceptHeaderVersion(HttpRequestMessage request)
{
var acceptHeader = request.Headers.Accept;
if (acceptHeader.Any())
{
var format = acceptHeader.First();
format.MediaType = JsonMediaTypeFormatter.DefaultMediaType.MediaType;
}
var heads = HttpContext.Current.Request.Headers;
if (heads.AllKeys.Contains("Version"))
{
return heads.GetValues("Version").FirstOrDefault();
}
return "";
}
}
            config.Routes.MapHttpRoute(
name: "DefaultApi",
routeTemplate: "api/{namespace}/{id}/{controller}/{subid}/{action}",
defaults: new { subid = RouteParameter.Optional, action = RouteParameter.Optional }
);
config.Routes.MapHttpRoute(
name: "AllApi",
routeTemplate: "api/{namespace}/{controller}",
defaults: new { }
);
config.Services.Replace(typeof(IHttpControllerSelector), new WebApiControllerSelector(config));

WebApi路由及版本控制的更多相关文章

  1. Net Core WebApi几种版本控制对比

    Net Core WebApi几种版本控制对比 一.版本控制的好处: (1)有助于及时推出功能, 而不会破坏现有系统. (2)它还可以帮助为选定的客户提供额外的功能. API 版本控制可以采用不同的方 ...

  2. C#进阶系列——WebApi 路由机制剖析:你准备好了吗?

    前言:从MVC到WebApi,路由机制一直是伴随着这些技术的一个重要组成部分. 它可以很简单:如果你仅仅只需要会用一些简单的路由,如/Home/Index,那么你只需要配置一个默认路由就能简单搞定: ...

  3. mvc webapi路由重写

    修改app_start/webapiconfig.cs using System.Web.Http; using System.Web.Routing; using Ninject; using Tx ...

  4. 【C#】 WebApi 路由机制剖析

    C#进阶系列——WebApi 路由机制剖析:你准备好了吗? 转自:https://blog.csdn.net/wulex/article/details/71601478 2017年05月11日 10 ...

  5. C#进阶系列——WebApi 路由机制剖析:你准备好了吗? 转载https://www.cnblogs.com/landeanfen/p/5501490.html

    阅读目录 一.MVC和WebApi路由机制比较 1.MVC里面的路由 2.WebApi里面的路由 二.WebApi路由基础 1.默认路由 2.自定义路由 3.路由原理 三.WebApi路由过程 1.根 ...

  6. WebApi 路由机制剖析

    阅读目录 一.MVC和WebApi路由机制比较 1.MVC里面的路由 2.WebApi里面的路由 二.WebApi路由基础 1.默认路由 2.自定义路由 3.路由原理 三.WebApi路由过程 1.根 ...

  7. WebApi路由机制详解

    随着前后端分离的大热,WebApi在项目中的作用也是越来越重要,由于公司的原因我之前一直没有机会参与前后端分离的项目,但WebApi还是要学的呀,因为这东西确实很有用,可单独部署.与前端和App交互都 ...

  8. MVC和WebApi路由机制比较

    1.MVC使用的路由 在MVC中,默认路由机制是通过解析url路径来匹配Action.比如:/User/GetList,这个url就表示匹配User控制器下的GetList方法,这是MVC路由的默认解 ...

  9. .net webapi 实现 接口版本控制并打通swagger支持

    我们在开发 webapi 项目时如果遇到 api 接口需要同时支持多个版本的时候,比如接口修改了入参之后但是又希望支持老版本的前端(这里的前端可能是网页,可能是app,小程序 等等)进行调用,这种情况 ...

随机推荐

  1. ** poj Y2K Accounting Bug 2586

    Y2K Accounting Bug Time Limit: 1000MS   Memory Limit: 65536K Total Submissions: 10117   Accepted: 50 ...

  2. redmine忘记username和password

    环境: Ubuntu 13.10 bitnami-redmine-2.5.1-1-linux-x64-installer.run 用bitnami安装完redmine以后,有是否忘记了username ...

  3. zTree市县实现三个梯级数据库映射

    zTree市县实现三个梯级数据库映射 Province.hbm.xml: <?xml version="1.0" encoding="UTF-8"? &g ...

  4. Ubuntu14.04下安装ZendStudio10.6.1+SVN出现Failed to load JavaHL Library

    Subclipse不能正常工作,打开后报错: Failed to load JavaHL Library. These are the errors that were encountered: no ...

  5. JAVA经BigDecimal圆角的解决方案及注意事项

    /** * @Description: 四舍五入住宿2小数位数 * @param valueName * @return */ public static Double formateDouble45 ...

  6. 国内外MD5在线解密网站

    -http://www.cmd5.com/english.aspx (457,354,352,282) - http://www.md5crack.com - http://www.hashcheck ...

  7. web引用和服务引用

    原文:web引用和服务引用 在VS2010环境下开发C#的winform程序或者WPF时,会碰到调用web引用的问题. 1.添加一个服务引用时,会在app.config里生成basicHttpBind ...

  8. 动软.NET 分页存储过程UP_GetRecordByPage

    1, ------------------------------------ --用途:支持任意排序的分页存储过程 --说明: ----------------------------------- ...

  9. WORD中怎样自己主动生成文件夹?

    步骤: 1.输入当做标题的文字 2.将文字设置为标题样式 3.光标放在要加入�文件夹的位置 4.选择插入->引用->索引和文件夹->文件夹->确定

  10. 玩转Web之servlet(二)---servlet常见错误

    1>403:tomcat发生错误 2> 404 :意思是服务器依据请求资源路径,找不到对应的资源        解决:1.依据http://localhost:8080/Web工程名/ur ...