WebApi路由及版本控制
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路由及版本控制的更多相关文章
- Net Core WebApi几种版本控制对比
Net Core WebApi几种版本控制对比 一.版本控制的好处: (1)有助于及时推出功能, 而不会破坏现有系统. (2)它还可以帮助为选定的客户提供额外的功能. API 版本控制可以采用不同的方 ...
- C#进阶系列——WebApi 路由机制剖析:你准备好了吗?
前言:从MVC到WebApi,路由机制一直是伴随着这些技术的一个重要组成部分. 它可以很简单:如果你仅仅只需要会用一些简单的路由,如/Home/Index,那么你只需要配置一个默认路由就能简单搞定: ...
- mvc webapi路由重写
修改app_start/webapiconfig.cs using System.Web.Http; using System.Web.Routing; using Ninject; using Tx ...
- 【C#】 WebApi 路由机制剖析
C#进阶系列——WebApi 路由机制剖析:你准备好了吗? 转自:https://blog.csdn.net/wulex/article/details/71601478 2017年05月11日 10 ...
- C#进阶系列——WebApi 路由机制剖析:你准备好了吗? 转载https://www.cnblogs.com/landeanfen/p/5501490.html
阅读目录 一.MVC和WebApi路由机制比较 1.MVC里面的路由 2.WebApi里面的路由 二.WebApi路由基础 1.默认路由 2.自定义路由 3.路由原理 三.WebApi路由过程 1.根 ...
- WebApi 路由机制剖析
阅读目录 一.MVC和WebApi路由机制比较 1.MVC里面的路由 2.WebApi里面的路由 二.WebApi路由基础 1.默认路由 2.自定义路由 3.路由原理 三.WebApi路由过程 1.根 ...
- WebApi路由机制详解
随着前后端分离的大热,WebApi在项目中的作用也是越来越重要,由于公司的原因我之前一直没有机会参与前后端分离的项目,但WebApi还是要学的呀,因为这东西确实很有用,可单独部署.与前端和App交互都 ...
- MVC和WebApi路由机制比较
1.MVC使用的路由 在MVC中,默认路由机制是通过解析url路径来匹配Action.比如:/User/GetList,这个url就表示匹配User控制器下的GetList方法,这是MVC路由的默认解 ...
- .net webapi 实现 接口版本控制并打通swagger支持
我们在开发 webapi 项目时如果遇到 api 接口需要同时支持多个版本的时候,比如接口修改了入参之后但是又希望支持老版本的前端(这里的前端可能是网页,可能是app,小程序 等等)进行调用,这种情况 ...
随机推荐
- 在JBuilder8在使用ANT
在JBuilder8中使用ANT 作者:翁驰原 在JBuilder8中.Ap ...
- 为什么MVC不是一种设计模式(转)
MVC(Model-View-Controller)是处理界面应用程序时常用的解决方案,构成了表示层. MVC通过分离模型.视图.控制器在应用程序中的角色,实现界面和业务逻辑的解耦.Model(是OO ...
- Centos6.5下一个Ceph存储集群结构
简单的介绍 Ceph的部署模式下主要包括下面几个类型的节点 • Ceph OSDs: A Ceph OSD 进程主要用来存储数据,处理数据的replication,恢复,填充.调整资源组合以及通过检查 ...
- [原创].NET 分布式架构开发实战之四 构建从理想和实现之间的桥梁(前篇)
原文:[原创].NET 分布式架构开发实战之四 构建从理想和实现之间的桥梁(前篇) .NET 分布式架构开发实战之四 构建从理想和实现之间的桥梁(前篇) 前言:上一篇文章讲述了一些实现DAL的理论,本 ...
- 跳转表C语言,不比redis版本号
本来跳表的原理很easy的(相对于红 - 黑树),但国庆间歇性地搞5天才捞起来-- 我学会了跳之前写表的链式结构完全基于,我看着写的过程中redis实现,它的每个键列都是用数组来表示的.细致想了想发现 ...
- 【转】介绍Jython,第一部分:轻轻松松写JAVA程序
本文转自:http://www.ibm.com/developerworks/cn/education/java/j-jython1/index.html 关于本教程 本教程介绍哪些内容? 这个两部分 ...
- grep之字符串搜索算法Boyer-Moore由浅入深(比KMP快3-5倍)(转)
这篇长文历时近两天终于完成了,前两天帮网站翻译一篇文章“为什么GNU grep如此之快?”,里面提及到grep速度快的一个重要原因是使用了Boyer-Moore算法作为字符串搜索算法,兴趣之下就想了解 ...
- iostream与iostream.h乱弹琴
#include <iostream.h> 非标准输出流 #include <iostream> 标准输出流 见短eclipse关于使用android ndk时的简单代码 ...
- Git--Submodule使用
项目模板中通常由前端保持,所以每次更新模板.我也要跟着变化项目. 随着时间的推移,这不是一个方法来找到,老这么维护.大型项目,更多的模板,真的很容易管理和维护. 然后头让我用submodule前端资源 ...
- nodejs http静态服务器
使用nodejs写的很简单的静态服务器,没有做cluster处理,没有做缓存处理,不支持访问文件夹,功能只有一个,就是获取到文件后再返回文件内容. var fs = require('fs'); va ...