前言

在ASP.NET、ASP.NET MVC和ASP.NET Web API这些框架中都会发现有路由的身影,它们的原理都差不多,只不过在不同的环境下作了一些微小的修改,这也是根据每个框架的特性来制定的,今天我们就来看一看路由的结构,虽然我在MVC系列里写过路由的篇幅不过在这里是Web API 路由对象介绍。

ASP.NET Web API路由、管道

  • ASP.NET Web API 开篇介绍示例
  • ASP.NET Web API 路由对象介绍
  • ASP.NET Web API 管道模型
  • ASP.NET Web API selfhost宿主环境中管道、路由
  • ASP.NET Web API webhost宿主环境中管道、路由

路由系统概念

路由对象的结构

图1

路由系统中最重要的部分也就是路由对象了,那我们首先就来看一下【路由对象】的定义,不管是在ASP.NET、ASP.NET MVC、还是ASP.NET Web API的路由系统中路由都要有个名称,其实这个名称并不是路由对象中的而是在注册路由信息的时候,添加到路由对象集合的时候需要的名称,这里也只是当作路由的一部分,这个大家知道就好了。

在生成路由对象的时候我们要给路由赋值URL模板,这也是共同的,也是必须的,至于约束URL模板的条件是可以根据自己情况来定义的。在生成的同时框架会给路由对象赋值上【路由请求处理程序】用以作为衔接路由系统和框架的主体功能部分。

注册路由到系统框架中

图2

在路由定义好之后,我们便会把它注册到系统框架中。

路由对象的URL匹配

图3

在路由对象注册到系统框架中之后,这个时候如果有外部的请求的到达,这个时候路由系统会让路由对象集合中每个路由对象对这个请求进行匹配,就如图4一样。

图4

这个时候就是路由对象所要能做出的行为就是URL的匹配,根据什么来匹配?是根据在路由对象实例化的时候定义好的URL模板和条件,拿请求信息的URL和自身定义的URL模板进行匹配,假使没有匹配成功则会返回Null,这个时候框架则会让下一个路由对象来进行匹配直到有匹配的成功为止,如果这个时候匹配成功了路由则会生成一个【路由数据对象】。

路由数据对象也很重要,因为后续的框架功能部分都是使用它的,它也是整个路由系统的结晶,我们看下图5

图5

路由数据对象会保持一个生成它的路由对象的引用,然后是Values的是保存着路由对象在经过URL匹配后的值,分别表示着URL片段的名字和对应的URL真实值,而DataTokens则是在路由对象定义生成的时候直接带过来的值,当然了路由请求处理程序也是由执行生成的路由对象带来的。

在ASP.NET、ASP.NET MVC、ASP.NET Web API这些框架中路由系统都是遵循着上面的所述的这样一个过程,只不过在不同的框架环境下使用的类型不同,做的处理也不太一样,但是整体的流程是一致的,下面附上图6说明了之间的类型的差异性,还有更多的细节就不一一展示了。

图6

还有在Web API(WebHost)环境下路由显示的是这样实质的本质其实又是ASP.NET的路由系统在支持的,这个会在后面的Web API系列篇幅中讲解。

下面简单的演示一下在各种框架环境下的路由对象注册,

ASP.NET:

RouteTable.Routes.MapPageRoute("ASP.NETRoute","ProductInfo/{action}/{id}","~/ProductInfo.aspx",true,new RouteValueDictionary { { "id", RouteParameter.Optional }, { "action", "show" } });

ASP.NET MVC:

            RouteTable.Routes.MapRoute("ASP.NETMVCRoute","ProductInfo/{action}/{id}",new { controller="Product",action="show",id=RouteParameter.Optional});

ASP.NET Web API(WEBHOST):

            GlobalConfiguration.Configuration.Routes.MapHttpRoute("WebAPIRoute","api/{controller}/{id}", new { id = RouteParameter.Optional });

ASP.NET Web API(SELFHOST):

HttpSelfHostConfiguration configuration = new HttpSelfHostConfiguration("http://loacalhost/selfhost");using (HttpSelfHostServer selfHostServer = new HttpSelfHostServer(configuration)){selfHostServer.Configuration.Routes.MapHttpRoute("DefaultApi", "api/{controller}/{id}", new { id=RouteParameter.Optional});selfHostServer.OpenAsync();Console.Read();}

ASP.NET Web API 路由系列对象

从上图的图表中就可以看出,ASP.NET Web API框架在不同的宿主环境下路由系统中所对应的对象类型是不同的,这里就先给大家介绍在SelfHost环境下的路由系统中的路由对象吧。

SelfHost宿主环境

Web API路由对象(System.Web.Http.Routing)

HttpRoute

    // 摘要://     表示自承载(即在 ASP.NET 之外承载)的路由类。public class HttpRoute : IHttpRoute{public HttpRoute(string routeTemplate, HttpRouteValueDictionary defaults, HttpRouteValueDictionary constraints, HttpRouteValueDictionary dataTokens, HttpMessageHandler handler);public IDictionary<string, object> Constraints { get; }public IDictionary<string, object> DataTokens { get; }public IDictionary<string, object> Defaults { get; }public HttpMessageHandler Handler { get; }public string RouteTemplate { get; }public virtual IHttpRouteData GetRouteData(string virtualPathRoot, HttpRequestMessage request);public virtual IHttpVirtualPathData GetVirtualPath(HttpRequestMessage request, IDictionary<string, object> values);protected virtual bool ProcessConstraint(HttpRequestMessage request, object constraint, string parameterName, HttpRouteValueDictionary values, HttpRouteDirection routeDirection);}

可以从上面的定义中看到HttpRoute对象就是代表着在Web API框架中的路由对象了,在HttpRoute类型定义的构造函数中的参数分别表示着路由模板、路由模板对应的默认值、路由匹配条件、注册的路由附带的值以及最后的Http请求处理程序,这几个参数值也分别对应着HttpRoute类型中的几个属性,这个自行看一下就明白了。

Web API路由对象集合(System.Web.Http)

HttpRouteCollection

HttpRouteCollectionExtensions

我们先来看一下HttpRouteCollection类型的扩展类型HttpRouteCollectionExtensions吧

    public static class HttpRouteCollectionExtensions{public static IHttpRoute MapHttpRoute(this HttpRouteCollection routes, string name, string routeTemplate);public static IHttpRoute MapHttpRoute(this HttpRouteCollection routes, string name, string routeTemplate, object defaults);public static IHttpRoute MapHttpRoute(this HttpRouteCollection routes, string name, string routeTemplate, object defaults, object constraints);public static IHttpRoute MapHttpRoute(this HttpRouteCollection routes, string name, string routeTemplate, object defaults, object constraints, HttpMessageHandler handler);}

这里大家可以对比上面的路由注册时的代码,就可以知道我们在路由集合 添加/注册 路由的时候是由HttpRouteCollectionExtensions类型的扩展方法来进行操作的,这个时候我们再看一下方法参数最多的那个MapHttpRoute()方法的实现:

public static IHttpRoute MapHttpRoute(this HttpRouteCollection routes, string name, string routeTemplate, object defaults, object constraints, HttpMessageHandler handler){if (routes == null){throw System.Web.Http.Error.ArgumentNull("routes");}HttpRouteValueDictionary dictionary = new HttpRouteValueDictionary(defaults);HttpRouteValueDictionary dictionary2 = new HttpRouteValueDictionary(constraints);IDictionary<string, object> dataTokens = null;HttpMessageHandler handler2 = handler;IHttpRoute route = routes.CreateRoute(routeTemplate, dictionary, dictionary2, dataTokens, handler2);routes.Add(name, route);return route;}

这里大家就可以看到了,HttpRoute对象的创建操作和添加操作是在这扩展方法里执行的,现在我们就可以去看一下HttpRouteCollection类型的定义了,看一下如何创建的IHttpRoute对象:

    public class HttpRouteCollection : ICollection<IHttpRoute>, IEnumerable<IHttpRoute>, IEnumerable, IDisposable{public HttpRouteCollection();public HttpRouteCollection(string virtualPathRoot);public virtual int Count { get; }public virtual bool IsReadOnly { get; }public virtual string VirtualPathRoot { get; }public virtual void Add(string name, IHttpRoute route);public IHttpRoute CreateRoute(string routeTemplate, object defaults, object constraints);public IHttpRoute CreateRoute(string routeTemplate, IDictionary<string, object> defaults, IDictionary<string, object> constraints, IDictionary<string, object> dataTokens);public virtual IHttpRoute CreateRoute(string routeTemplate, IDictionary<string, object> defaults, IDictionary<string, object> constraints, IDictionary<string, object> dataTokens, HttpMessageHandler handler);public virtual IHttpRouteData GetRouteData(HttpRequestMessage request);}

这里只是其中的一部分,下面我们就来看一下具体的实现,其实就是实例化一个HttpRoute路由对象根据用户配置的参数信息:

public virtual IHttpRoute CreateRoute(string routeTemplate, IDictionary<string, object> defaults, IDictionary<string, object> constraints, IDictionary<string, object> dataTokens, HttpMessageHandler handler){HttpRouteValueDictionary dictionary = new HttpRouteValueDictionary(defaults);HttpRouteValueDictionary dictionary2 = new HttpRouteValueDictionary(constraints);return new HttpRoute(routeTemplate, dictionary, dictionary2, new HttpRouteValueDictionary(dataTokens), handler);}

这是路由对象集合类型的第一个作用就是添加/注册 路由信息,那么第二个呢?就是根据请求信息来匹配路由对象,上面也说过了,其实真正根据请求来匹配的并不是路由对象集合类型(HttpRouteCollection),而是在其中的每个路由,我们看一下HttpRouteCollection的障眼法:

public virtual IHttpRouteData GetRouteData(HttpRequestMessage request){if (request == null){throw System.Web.Http.Error.ArgumentNull("request");}foreach (IHttpRoute route in this._collection){IHttpRouteData routeData = route.GetRouteData(this._virtualPathRoot, request);if (routeData != null){return routeData;}}return null;}

从这里可以看出在路由匹配完成后会返回一个实现IHttpRouteDatarouteData接口的对象,也就是上面所说的路由数据对象。

Web API路由数据对象(System.Web.Http.Routing)

HttpRouteData

    public class HttpRouteData : IHttpRouteData{public HttpRouteData(IHttpRoute route);public HttpRouteData(IHttpRoute route, HttpRouteValueDictionary values);public IHttpRoute Route { get; }public IDictionary<string, object> Values { get; }}

其实这里都不用讲了,上面都讲过了,HttpRouteData对象包含着生成它的路由对象(HttpRoute)的引用,并且Values值就是经过匹配过后的路由模板值,key键对应着Url模板的片段值,value对应着的是片段对应的真实值。

SelfHost环境下的路由就说到这里,大家看一下如下的示意图,简单的表示了在SelfHost环境下路由的一个处理过程,具体的细节会在后面的篇幅讲解。

图7

WebHost宿主环境

 

Web API路由对象(System.Web.Http.WebHost.Routing)

HostedHttpRoute

    internal class HostedHttpRoute : IHttpRoute{// Methodspublic HostedHttpRoute(string uriTemplate, IDictionary<string, object> defaults, IDictionary<string, object> constraints, IDictionary<string, object> dataTokens, HttpMessageHandler handler);public IHttpRouteData GetRouteData(string rootVirtualPath, HttpRequestMessage request);public IHttpVirtualPathData GetVirtualPath(HttpRequestMessage request, IDictionary<string, object> values);// Propertiespublic IDictionary<string, object> Constraints { get; }public IDictionary<string, object> DataTokens { get; }public IDictionary<string, object> Defaults { get; }public HttpMessageHandler Handler { get; private set; }internal Route OriginalRoute { get; private set; }public string RouteTemplate { get; }
}

从上面的代码定义中可以看到HostedHttpRoute是程序集内部类型,并且是直接继承自IHttpRoute接口,跟SelfHost环境中的HttpRoute对象是一点关系都没有。

从它定义的内部结构来看它跟HttpRoute对象的结构相似,还是那些属性那些个对象,唯一不同的就是多了个OriginalRoute的只读属性(对于外部来说),这个属性也就是封装的HttpWebRoute对象,看下封装时的实现

public HostedHttpRoute(string uriTemplate, IDictionary<string, object> defaults, IDictionary<string, object> constraints, IDictionary<string, object> dataTokens, HttpMessageHandler handler){RouteValueDictionary dictionary = (defaults != null) ? new RouteValueDictionary(defaults) : null;RouteValueDictionary dictionary2 = (constraints != null) ? new RouteValueDictionary(constraints) : null;RouteValueDictionary dictionary3 = (dataTokens != null) ? new RouteValueDictionary(dataTokens) : null;this.OriginalRoute = new HttpWebRoute(uriTemplate, dictionary, dictionary2, dictionary3, HttpControllerRouteHandler.Instance, this);this.Handler = handler;}

在HostedHttpRoute对象构造函数中可以清楚的看到OriginalRoute属性是赋值的HttpWebRoute对象的实例,我们现在就来看一下HttpWebRoute对象的定义

    internal class HttpWebRoute : Route{// Fieldsinternal const string HttpRouteKey = "httproute";// Methodspublic HttpWebRoute(string url, RouteValueDictionary defaults, RouteValueDictionary constraints, RouteValueDictionary dataTokens, IRouteHandler routeHandler, IHttpRoute httpRoute);private static HttpRouteDirection ConvertRouteDirection(RouteDirection routeDirection);private static RouteValueDictionary GetRouteDictionaryWithoutHttpRouteKey(IDictionary<string, object> routeValues);public override VirtualPathData GetVirtualPath(RequestContext requestContext, RouteValueDictionary values);protected override bool ProcessConstraint(HttpContextBase httpContext, object constraint, string parameterName, RouteValueDictionary values, RouteDirection routeDirection);// Propertiespublic IHttpRoute HttpRoute { get; private set; }
}

从这里可以看到HttpWebRoute对象继承自ASP.NET中的Route对象,现在就可以理解为HostedHttpRoute对象持有对ASP.NET中Route对象的引用,而在HostedHttpRoute的构造函数实现中,对OriginalRoute属性是赋值实例化的时候,在最后传入了一个HttpControllerRouteHandler类型的路由处理程序,实则是给ASP.NET中的Route对象的路由处理程序(Routehandler属性)进行的赋值。这里路由的具体的操作后续篇幅中会有讲到一个全面的过程。

Web API路由对象集合(System.Web.Http.WebHost.Routing

HostedHttpRouteCollection

internal class HostedHttpRouteCollection : HttpRouteCollection{// Fieldsprivate readonly RouteCollection _routeCollection;// Methodspublic HostedHttpRouteCollection(RouteCollection routeCollection);public override void Add(string name, IHttpRoute route);public override void Clear();public override bool Contains(IHttpRoute item);public override bool ContainsKey(string name);public override void CopyTo(IHttpRoute[] array, int arrayIndex);public override void CopyTo(KeyValuePair<string, IHttpRoute>[] array, int arrayIndex);public override IHttpRoute CreateRoute(string uriTemplate, IDictionary<string, object> defaults, IDictionary<string, object> constraints, IDictionary<string, object> dataTokens, HttpMessageHandler handler);public override IEnumerator<IHttpRoute> GetEnumerator();public override IHttpRouteData GetRouteData(HttpRequestMessage request);public override IHttpVirtualPathData GetVirtualPath(HttpRequestMessage request, string name, IDictionary<string, object> values);public override void Insert(int index, string name, IHttpRoute value);private static NotSupportedException NotSupportedByHostedRouteCollection();private static NotSupportedException NotSupportedByRouteCollection();public override bool Remove(string name);public override bool TryGetValue(string name, out IHttpRoute route);// Propertiespublic override int Count { get; }public override IHttpRoute this[string name] { get; }public override IHttpRoute this[int index] { get; }public override string VirtualPathRoot { get; }}

看到这里的代码定义,HostedHttpRouteCollection对象同样也是程序集内部类型,继承自ASP.NET中的RouteCollection对象,这里要说是CreateRoute()方法和GetRouteData()方法返回的分别是HostedHttpRoute对象和HostedHttpRouteData对象,其实在GetRouteData()方法中起初生成的就是Routedata对象,只不过在返回的时候经过HostedHttpRouteData对象封装了一下。

Web API路由数据对象(System.Web.Http.WebHost.Routing)

HostedHttpRouteData

这里我们看一下HostedHttpRouteData类型的定义:

        internal class HostedHttpRouteData : IHttpRouteData{// Methodspublic HostedHttpRouteData(RouteData routeData);// Propertiesinternal RouteData OriginalRouteData { get; private set; }public IHttpRoute Route { get; private set; }public IDictionary<string, object> Values { get; }}

从构造函数的定义就可以看出来是HostedHttpRouteData是封装的RouteData对象,这些路由流程细节后面篇幅中会有讲解。

最后我们看一下在WebHost宿主环境下的路由示意图。

图8

ASP.NET Web API 路由对象介绍相关推荐

  1. ASP.NET Web API 开篇示例介绍

    ASP.NET Web API 开篇示例介绍 ASP.NET Web API 对于我这个初学者来说ASP.NET Web API这个框架很陌生又熟悉着. 陌生的是ASP.NET Web API是一个全 ...

  2. Asp.net Web Api 路由 和 异常处理

    一.路由: 新建一个ASP.NET MVC4 Web Application项目之后,我们会发现在网站根目录下有个App_Start文件夹.找到下面的RouteConfig.cs文件,如下: publ ...

  3. ASP.NET Web API路由规则(二)

    默认的规则 在ASP.NET MVC4中 global.asax.cs代码中并无注册默认路由规则的代码 代码如下: public class WebApiApplication : System.We ...

  4. ASP.NET Web API WebHost宿主环境中管道、路由

    ASP.NET Web API WebHost宿主环境中管道.路由 前言 上篇中说到ASP.NET Web API框架在SelfHost环境中管道.路由的一个形态,本篇就来说明一下在WebHost环境 ...

  5. ASP.NET Web API Selfhost宿主环境中管道、路由

    ASP.NET Web API Selfhost宿主环境中管道.路由 前言 前面的几个篇幅对Web API中的路由和管道进行了简单的介绍并没有详细的去说明一些什么,然而ASP.NET Web API这 ...

  6. ASP.NET Web API的Controller是如何被创建的?

    Web API调用请求的目标是定义在某个HttpController类型中的某个Action方法,所以消息处理管道最终需要激活目标HttpController对象.调用请求的URI会携带目标HttpC ...

  7. 《ASP.NET Web API 2框架揭秘》

    <ASP.NET Web API 2框架揭秘> 基本信息 作者: 蒋金楠 出版社:电子工业出版社 ISBN:9787121235368 上架时间:2014-7-5 出版日期:2014 年7 ...

  8. ASP NET Web API 2框架揭秘

    ASP.NET Web API2框架揭秘(.NET领域再现力作顶级专家精讲微软全新轻量级通信平台) 蒋金楠 著   ISBN 978-7-121-23536-8 2014年7月出版 定价:108.00 ...

  9. ASP.NET Web API 2 入门教程

    译者:jiankunking 出处:http://blog.csdn.net/jiankunking 源码下载 HTTP不仅提供web页面服务,在构建公开服务和数据api方面,它也是一个强大的平台.H ...

最新文章

  1. php注解rbac,PHP的RBAC权限详解
  2. .NET Core 3.0中用 Code-First 方式创建 gRPC 服务与客户端
  3. html流式布局插件,Jquery瀑布流网格布局插件
  4. WPF 程序最大化,窗口,最小化
  5. C语言printf控制光标位置和清空屏幕
  6. complete_code_Chapter1
  7. Android反编译与加密(代码混淆)
  8. 实现一个HTTP服务器的Demo
  9. D8(YT88)加密狗破解与加密工具
  10. 函数发生器输出电压值会与设定值不同
  11. Unity 2D图片添加加外边框Shader
  12. obv代码matlab,obv指标源代码,标准obv指标源代码
  13. 17个获取设计灵感创意必备网站
  14. 计算机逻辑模块,常用时序逻辑电路模块 《计算机结构与 及逻辑设计》课件.ppt...
  15. 360欺骗4亿网民 胡乱解读“超级工厂”病毒 ——卡巴斯基关于360胡乱解读“超级工厂”的声明
  16. MySQL数据库怎么查看er图表_详解 Navicat 查看方式之ER图表
  17. 调整Xmind试用日期
  18. 《Linux就该这么学》36期学员
  19. 新华字典 - Windows Phone
  20. windows忘记电脑密码解决办法

热门文章

  1. c语言编程中tem代表什么意思,“CTEM”是“Conventional Transmission Electron Microscopy”的缩写,意思是“常规透射电子显微镜”...
  2. 万字大白话带你重拾JVM
  3. 互联网各大公司职级和薪资一览
  4. 聊聊Spring事务失效的12种场景,太坑人了
  5. assert python 中断_Python这十大装B语法!你不会还没有听过吧?
  6. c swap方法在哪个库里面_在编程竞赛中高效地编写C/C ++代码
  7. 磁盘分区形式mbr和gpt哪个好_济南历下区中考美术集训应该选哪个
  8. 电脑ip地址设置_关于电脑的远程开机(唤醒)
  9. c 结构体 不允许使用不完整的类型_C语言必学知识点 quot;结构体quot;详细解析!...
  10. 对计算机上的浏览器的介绍,Edge浏览器的前世今生 史上最全Edge浏览器介绍