[Web API] Web API 2 深入系列(5) 特性路由
2016-10-18 21:29
330 查看
目录
特性路由的目的在于更好的提供restful架构的接口,最近好忙(懒),所以更新速度慢.
普通变量
a/b/{c}
缺省变量
a/b/{c=d}
变量约束
a/b/{c:int:range(10,20)}
通配符
a/b/{*c:datetime}
[RoutePrefix("api/demo")] :定义路由前缀
当调用MapHttpAttributeRoutes方法时,WebAPI会创建1个唯一的RouteCollectionRoute作为IHttpRoute并添加到路由表中.
MapHttpAttributeRoutes方法:
RouteCollectionRoute是特性路由的HttpRoute对象,既是一个IHttpRoute对象,又是一个IHttpRoute集合.并且其中核心方法为GetRouteData(IHttpRoute其他接口都返回为null),
在该方法中,我们发现RouteCollectionRoute调用了内部所有的SubRoutes对象.
而其内部的SubRoutes类型实际为SubRouteCollection类型
而SubRoutes的创建是在MapHttpAttributeRoutes方法定义,实际调用是在HttpServer的Send方法初始化的.
首先验证一下我们的特性路由注册位置(定义1个扩展方法)
先看下DataTokens上有哪些东西.
截图:
对于DataTokens的actions和precedence的属性,在DirectRouteBuilder的Build方法中实现
其中actions表示该路由模板对应的actiondescription(在特性路由中,会为每个controller创建独立的一份子路由.)
而precedence表示匹配的优先级,对于有约束的优先级高于无优先级.(约束分为常量,变量,通配符)
在前2节中,我们讲了如何选择Action以及Controller.
实际上,如果使用特性路由.选择的机制又有些变化.
备注:
- 如果我们为特性路由指定了Name,则会自动创建一个IHttpRoute绑定到RouteCollection上.(这步是在HttpConfiguration初始化中最后做判断完成的)
首发地址:http://neverc.cnblogs.com/p/5975086.html
1. 特性路由注册 2. 路由解析 - 生成DataTokens - 选择HttpController - 选择Action
特性路由的目的在于更好的提供restful架构的接口,最近好忙(懒),所以更新速度慢.
特性路由注册
[Route(模板)] :定义特性路由模板普通变量
a/b/{c}
缺省变量
a/b/{c=d}
变量约束
a/b/{c:int:range(10,20)}
通配符
a/b/{*c:datetime}
[RoutePrefix("api/demo")] :定义路由前缀
路由解析
通过IRoutePrefix/IHttpRouteInfoProvider,我们可以直接注册路由,映射到具体的Controller和Action.当调用MapHttpAttributeRoutes方法时,WebAPI会创建1个唯一的RouteCollectionRoute作为IHttpRoute并添加到路由表中.
MapHttpAttributeRoutes方法:
public static void MapHttpAttributeRoutes(HttpConfiguration configuration, IInlineConstraintResolver constraintResolver, IDirectRouteProvider directRouteProvider) { RouteCollectionRoute aggregateRoute = new RouteCollectionRoute(); configuration.Routes.Add("MS_attributerouteWebApi", (IHttpRoute) aggregateRoute); Action<HttpConfiguration> previousInitializer = configuration.Initializer; configuration.Initializer = (Action<HttpConfiguration>) (config => { previousInitializer(config); aggregateRoute.EnsureInitialized((Func<IReadOnlyCollection<IHttpRoute>>) (() => { subRoutes = new SubRouteCollection(); AttributeRoutingMapper.AddRouteEntries(subRoutes, configuration, constraintResolver, directRouteProvider); return subRoutes; })); }); }
RouteCollectionRoute是特性路由的HttpRoute对象,既是一个IHttpRoute对象,又是一个IHttpRoute集合.并且其中核心方法为GetRouteData(IHttpRoute其他接口都返回为null),
internal class RouteCollectionRoute : IHttpRoute, IReadOnlyCollection<IHttpRoute>, IEnumerable<IHttpRoute>, IEnumerable { public IHttpRouteData GetRouteData(string virtualPathRoot, HttpRequestMessage request) { List<IHttpRouteData> httpRouteDataList = new List<IHttpRouteData>(); //调用内部的SubRoutes对象 foreach (IHttpRoute subRoute in (IEnumerable<IHttpRoute>) this.SubRoutes) { IHttpRouteData routeData = subRoute.GetRouteData(virtualPathRoot, request); httpRouteDataList.Add(routeData); } return (IHttpRouteData) new RouteCollectionRoute.RouteCollectionRouteData((IHttpRoute) this, httpRouteDataList.ToArray()); } }
在该方法中,我们发现RouteCollectionRoute调用了内部所有的SubRoutes对象.
而其内部的SubRoutes类型实际为SubRouteCollection类型
internal class SubRouteCollection : IReadOnlyCollection<IHttpRoute>, IEnumerable<IHttpRoute>, IEnumerable { private readonly List<IHttpRoute> _routes = new List<IHttpRoute>(); private readonly List<RouteEntry> _entries = new List<RouteEntry>(); public IReadOnlyCollection<RouteEntry> Entries{get;} }
而SubRoutes的创建是在MapHttpAttributeRoutes方法定义,实际调用是在HttpServer的Send方法初始化的.
protected override async Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken) { this.EnsureInitialized(); //... }
首先验证一下我们的特性路由注册位置(定义1个扩展方法)
public static class RouteCollectionExt { public static IEnumerable<IHttpRoute> GetSubRoutes(this HttpRouteCollection routes) { var route = routes["MS_attributerouteWebApi"]; var prop = route.GetType().GetProperty("SubRoutes", BindingFlags.Instance | BindingFlags.NonPublic); var subRoutes = prop.GetValue(route) as IEnumerable<IHttpRoute>; return subRoutes; } }
生成DataTokens
DataTokens这次发挥了一定的作用,同时也告诉我们该如何使用它. (在第1节中,我觉得DataTokens是个冗余设计)先看下DataTokens上有哪些东西.
private static void ShowSubRoutesTokens(HttpRouteCollection routes) { foreach (var subRoute in routes.GetSubRoutes()) { Console.WriteLine(subRoute.RouteTemplate); foreach (var dataToken in subRoute.DataTokens) { Console.WriteLine("{0,-12}{1}", dataToken.Key, dataToken.Value); } Console.WriteLine(); } }
截图:
对于DataTokens的actions和precedence的属性,在DirectRouteBuilder的Build方法中实现
其中actions表示该路由模板对应的actiondescription(在特性路由中,会为每个controller创建独立的一份子路由.)
而precedence表示匹配的优先级,对于有约束的优先级高于无优先级.(约束分为常量,变量,通配符)
在前2节中,我们讲了如何选择Action以及Controller.
实际上,如果使用特性路由.选择的机制又有些变化.
选择HttpController
public virtual HttpControllerDescriptor SelectController(HttpRequestMessage request) { IHttpRouteData routeData = request.GetRouteData(); if (routeData != null) { //在GetDirectRouteController内获取了特性路由对应的Controller,同时要求匹配的所有特性路由对应的Controller为同一个 HttpControllerDescriptor directRouteController = DefaultHttpControllerSelector.GetDirectRouteController(routeData); return directRouteController; } //普通路由方式 string controllerName = this.GetControllerName(request); //... }
选择Action
public HttpActionDescriptor SelectAction(HttpControllerContext controllerContext) { var matchingActions = this.FindMatchingActions(controllerContext, false); //... } private List<ApiControllerActionSelector.CandidateActionWithParams> FindMatchingActions(HttpControllerContext controllerContext, bool ignoreVerbs = false) { //此处做特性路由判断 IEnumerable<IHttpRouteData> subRoutes = controllerContext.RouteData.GetSubRoutes(); return subRoutes == null ? 普通路由 : 特性路由; }
备注:
- 如果我们为特性路由指定了Name,则会自动创建一个IHttpRoute绑定到RouteCollection上.(这步是在HttpConfiguration初始化中最后做判断完成的)
- 文章中的代码并非完整WebAPI代码,一般是经过自己精简后的. - 本篇内容使用MarkDown语法编辑
首发地址:http://neverc.cnblogs.com/p/5975086.html
相关文章推荐
- ASP.NET Web API实践系列04,通过Route等特性设置路由
- [Web API] Web API 2 深入系列(1) 路由
- [Web API] Web API 2 深入系列(1) 路由
- ASP.NET Web API实践系列04,通过Route等特性设置路由
- [原创-总结]深入理解C# 3.x的新特性系列总结
- 【Web API系列教程】2.1 — ASP.NET Web API中的路由机制
- C# 语言特性系列(10) 深入理解默认值 Default Values
- .NET-全球化与本地化-深入研究系列(2) ASP.NET 2.0 本地化新特性
- C# 语言特性系列(6) 深入理解密封方法 sealed
- [Web API] Web API 2 深入系列(2) 消息管道
- ASP.NET Web API 中 特性路由(Attribute Routing) 的重名问题
- [Web API] Web API 2 深入系列(4) Action的选择
- C# 语言特性系列(3) 深入理解继承
- WebApi深入学习--特性路由
- Android 源码系列之<九>从源码的角度深入理解Activity的launchModel特性
- 【Web API系列教程】2.2 — ASP.NET Web API中的路由和动作选择机制
- C# 语言特性系列(5) 深入理解重写方法 override
- C# 语言特性系列(4) 深入理解虚方法
- C# 语言特性系列(9) 深入理解局部变量
- 《深入理解C# 3.x的新特性》博文系列汇总