ASP.NET Web API 路由对象介绍

前言

在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
{
// Methods
public 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); // Properties
public 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
{
// Fields
internal const string HttpRouteKey = "httproute"; // Methods
public 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); // Properties
public 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
{
// Fields
private readonly RouteCollection _routeCollection; // Methods
public 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); // Properties
public 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
{
// Methods
public HostedHttpRouteData(RouteData routeData); // Properties
internal RouteData OriginalRouteData { get; private set; }
public IHttpRoute Route { get; private set; }
public IDictionary<string, object> Values { get; }
}

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

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

图8

作者:金源

出处:http://www.cnblogs.com/jin-yuan/

本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面

ASP.NET Web API 路由对象介绍的更多相关文章

  1. ASP.NET Web API 框架研究 ASP.NET Web API 路由

    ASP.NET Web API 核心框架是一个独立的.抽象的消息处理管道,ASP.NET Web API有自己独立的路由系统,是消息处理管道的组成部分,其与ASP.NET路由系统有类似的设计,都能找到 ...

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

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

  3. ASP.NET Web API路由系统:路由系统的几个核心类型

    虽然ASP.NET Web API框架采用与ASP.NET MVC框架类似的管道式设计,但是ASP.NET Web API管道的核心部分(定义在程序集System.Web.Http.dll中)已经移除 ...

  4. ASP.NET Web API路由系统:Web Host下的URL路由

    ASP.NET Web API提供了一个独立于执行环境的抽象化的HTTP请求处理管道,而ASP.NET Web API自身的路由系统也不依赖于ASP.NET路由系统,所以它可以采用不同的寄宿方式运行于 ...

  5. ASP.NET Web API 路由

    路由系统是请求消息进入ASP.NET Web API消息处理管道的第一道屏障,其根本目的是利用注册的路由表(RouteTable)对请求的URI进行解析以确定目标HttpController和Acti ...

  6. Asp.Net Web APi 路由的特点

    在ASP.NET Web API中,路由是基于HTTP协议 GET请求路由到以GET开头的控制器方法,POST请求路由到以POST开头的控制器方法中,GET方法和GetProducts,都能与GET请 ...

  7. ASP.NET Web API路由解析

    前言 本篇文章比较长,仔细思考阅读下来大约需要15分钟,涉及类图有可能在手机显示不完整,可以切换电脑版阅读. 做.Net有好几年时间了从ASP.NET WebForm到ASP.NET MVC再到ASP ...

  8. 剖析Asp.Net Web API路由系统---WebHost部署方式

    上一篇我们剖析了Asp.Net路由系统,今天我们再来简单剖析一下Asp.Net Web API以WebHost方式部署时,Asp.Net Web API的路由系统内部是怎样实现的.还是以一个简单实例开 ...

  9. 解决ASP.NET Web API Json对象循环参考错误

    前言 一般我们在开法 ASP.NET Web API 时,如果是使用 Entity Framework 技术来操作数据库的话,当两个 Entity 之间包含导览属性(Navigation Proper ...

随机推荐

  1. 如何一步一步用DDD设计一个电商网站(三)—— 初涉核心域

    一.前言 结合我们本次系列的第一篇博文中提到的上下文映射图(传送门:如何一步一步用DDD设计一个电商网站(一)—— 先理解核心概念),得知我们这个电商网站的核心域就是销售子域.因为电子商务是以信息网络 ...

  2. 在Openfire上弄一个简单的推送系统

    推送系统 说是推送系统有点大,其实就是一个消息广播功能吧.作用其实也就是由服务端接收到消息然后推送到订阅的客户端. 思路 对于推送最关键的是服务端向客户端发送数据,客户端向服务端订阅自己想要的消息.这 ...

  3. .Net 分布式云平台基础服务建设说明概要

    1)  背景 建设云平台的基础框架,用于支持各类云服务的业务的构建及发展. 2)  基础服务 根据目前对业务的理解和发展方向,总结抽象出以下几个基础服务,如图所示 3)  概要说明 基础服务的发展会根 ...

  4. autocomplete的使用

    autocomplete使用分为本地调用方法和读取远程读取数据源的方法 (1)本地调用方法 <script src="Scripts/jquery-1.4.1.min.js" ...

  5. UML图中经常用到几种的关系图例

    学习这个东西挺奇怪的,时间一长就容易忘记,或者记不清楚.今天看到一些UML图的关系,发现有些出入了,索性就写下来,以后再忘记的时候过来看看. 在UML的类图中,常见的有以下几种关系: 继承(Gener ...

  6. animate.css(第三方动画使用方法)

    p.p1 { margin: 0.0px 0.0px 0.0px 0.0px; font: 17.0px Monaco; color: #a5b2b9 } animation 语法: animatio ...

  7. Linux上课笔记--随手记Linux命令

    初次接触Linux就是感觉这系统不够友好不够人性化,因为首先接触电脑就是win,图形化界面什么操作都可以清晰看到.随着更多的接触越来越发现Linux的强大,虽然我只是一个小白,可我就是爱上他了.现在就 ...

  8. Concurrency

    <Concurrency>:http://docs.oracle.com/javase/tutorial/essential/concurrency/index.html <Java ...

  9. Jquery EasyUI 开发实录

    有好几年没有用过EasyUI了,最近在外包做的一个项目中新增功能时,又用到了,本以为和按照以前那样用就可以了,可当我真正用的时候,发现许多地方不一样了,就连官网的文档都更新了,最突出的就是不知道什么时 ...

  10. 学习笔记:7z在delphi的应用

    最近做个发邮件的功能,需要将日志文件通过邮件发送回来用于分析,但是日志文件可能会超级大,测算下来一天可能会有800M的大小.所以压缩是不可避免了,delphi中的默认压缩算法整了半天不太好使,就看了看 ...