public class WebApiControllerSelector : IHttpControllerSelector
{
private const string NamespaceKey = "version";
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 = request.Headers;
if (heads.Contains("Version"))
{
return heads.GetValues("Version").FirstOrDefault();
}
return "";
}
}

路由:

         // Configure Web API for self-host. 

            Config.Routes.MapHttpRoute(
name: "DefaultApi",
routeTemplate: "api/oauth2/{version}/{controller}/{action}",
defaults: new { controller = RouteParameter.Optional, action = RouteParameter.Optional }
); Config.Services.Replace(typeof(IHttpControllerSelector), new WebApiControllerSelector(Config));

Owin WebApi版本控制的更多相关文章

  1. ASP.NET Linux部署(2) - MS Owin + WebApi + Mono + Jexus

    ASP.NET Linux部署(2) - MS Owin + WebApi + Mono + Jexus 本文承接我的上一篇博文: ASP.NET 5 Linux部署,那篇文章主要是针对最新的ASP. ...

  2. (转)基于OWIN WebAPI 使用OAuth授权服务【客户端模式(Client Credentials Grant)】

    适应范围 采用Client Credentials方式,即应用公钥.密钥方式获取Access Token,适用于任何类型应用,但通过它所获取的Access Token只能用于访问与用户无关的Open ...

  3. 基于OWIN WebAPI 使用OAuth授权服务【客户端验证授权(Resource Owner Password Credentials Grant)】

    适用范围 前面介绍了Client Credentials Grant ,只适合客户端的模式来使用,不涉及用户相关.而Resource Owner Password Credentials Grant模 ...

  4. 基于OWIN WebAPI 使用OAuth授权服务【客户端模式(Client Credentials Grant)】

    适应范围 采用Client Credentials方式,即应用公钥.密钥方式获取Access Token,适用于任何类型应用,但通过它所获取的Access Token只能用于访问与用户无关的Open ...

  5. ASP.NET Core WebApi版本控制

    前言: 在日常项目开发中,随着项目需求不断的累加.不断的迭代:项目服务接口需要向下兼容历史版本:前些时候就因为Api接口为做版本管理导致接口对低版本兼容处理不友好. 最近就像了解下如何实现WebApi ...

  6. 【干货】基于Owin WebApi 使用OAuth2进行客户端授权服务

    前言:采用Client Credentials方式,即密钥key/password,场景一般是分为客户端限制必须有权限才能使用的模块,这和微信公众号开放平台很类似. 让用户通过客户端去获取自己的tok ...

  7. 电商系统架构总结4(webapi 版本控制)

    为了 顺利迭代升级,web api 在维护过程是不断升级的,但用户是不能强迫他们每次都跟随你去升级,这样会让用户不胜其烦.为了保证不同版本的客户端能同时兼容,在web api接口上加入版本控制就很有必 ...

  8. Asp.net WebApi版本控制

    有关web api的版本控制网上有很多,如Web API 版本控制的几种方式 Web API 版本化的介绍 但是具体的code并不多,或者说可以run的demo 不多. 版本控制如果项目一开始还好做关 ...

  9. Owin WebAPI上传文件

    Owin是微软出了几年的东东了,一直没时间学习.大概了解了下,是一个脱离IIS环境,快速搭建WebAPI服务的东西. 刚好想尝试下尽量脱离IIS创建简单快捷配置的项目,就是用了Nginx+Owin的模 ...

随机推荐

  1. 【CF938G】Shortest Path Queries(线段树分治,并查集,线性基)

    [CF938G]Shortest Path Queries(线段树分治,并查集,线性基) 题面 CF 洛谷 题解 吼题啊. 对于每个边,我们用一个\(map\)维护它出现的时间, 发现询问单点,边的出 ...

  2. Luogu 3373 又乘又加的线段树

    Luogu 3373 又乘又加的线段树 当给一个节点加上一个加法标记时,直接把加法标记 += 新值: 当给一个节点加上一个乘法标记时,把乘法标记和加法标记同时 *= 新值.(注意pushdown函数中 ...

  3. 51nod 1563 坐标轴上的最大团(今日gg模拟第一题) | 线段覆盖 贪心 思维题

    51nod 1563 坐标轴上的最大团 坐标轴上有n个点,每个点有一个权值.第i个点的坐标是 xi ,权值是 wi .现在对这些点建图.对于点对 (i,j) ,如果 |xi−xj|≥wi+wj ,那么 ...

  4. BZOJ3601 一个人的数论 【数论 + 高斯消元】

    题目链接 BZOJ3601 题解 挺神的 首先有 \[ \begin{aligned} f(n) &= \sum\limits_{x = 1}^{n} x^{d} [(x,n) = 1] \\ ...

  5. 20135239 Linux内核分析 期中总结

    期中总结 链接 网易云课堂 MOOC 摘录与实验内容 第一周: http://www.cnblogs.com/20135239-yxlm/p/5216842.html 第二周: http://www. ...

  6. SpringMVC 使用@ResponseBody返回json 中文乱码

    这确实是个蛋疼的问题,Spring中解析字符串的转换器默认编码居然是ISO-8859-1 既然找到问题了,那就必须想办法改过来,不同版本的Spring好像方法还不一样,网上不少说的都是Spring3. ...

  7. 850. 矩形面积 II

    我们给出了一个(轴对齐的)矩形列表 rectangles . 对于 rectangle[i] = [x1, y1, x2, y2],其中(x1,y1)是矩形 i 左下角的坐标,(x2,y2)是该矩形右 ...

  8. 哲学家问题(java)的三个解法

    //加synchronize进行同步 //释放资源又很快获得自身的资源,这样不妥,吃完的话休息100ms //每个人先申请编号小的筷子 public class Philosopher impleme ...

  9. nltk30_Investigating bias with NLTK

    sklearn实战-乳腺癌细胞数据挖掘(博客主亲自录制视频教程) https://study.163.com/course/introduction.htm?courseId=1005269003&a ...

  10. jdk与jdt

    jdk是java的开发环境 ,程序的编译.运行都需要jdk.一个java开发平台,jdk少不了,而编辑器 可以多种多样,除了 eclipse中的JDT,还有独立的jcreate ,或者用记事本以其他加 ...