ASP.NET Web API的消息处理管道: HttpRoutingDispatcher
ASP.NET Web API的消息处理管道: HttpRoutingDispatcher
认情况下,作为消息处理管道“龙头”的HttpServer的Dispatcher属性返回一个HttpRoutingDispatcher对象,该对象可以视为这个消息处理管道的最后一个非DelegatingHandler类型的HttpMessageHandler。用户的调用请求一般都是针对定义在某个HttpController中的某个Action方法,所以消息处理管道最终需要激活相应的HttpController并执行对应的Action方法,而这些是通过HttpRoutingDispatcher来完成的。[本文已经同步到《How ASP.NET Web API Works?》]
如下面的代码片断所示,HttpRoutingDispatcher并不是DelegatingHandler的继承者,而是直接继承自HttpMessageHandler。我们在构建一个HttpRoutingDispatcher对象的时候需要指定一个HttpConfiguration对象,而通过参数defaultHandler指定的HttpMessageHandler对于创建的HttpRoutingDispatcher对象来说具有重要的意义,HttpController的激活、Action方法的选择与执行等后续操作实际上是由它来完成的。
1: public class HttpRoutingDispatcher : HttpMessageHandler
2: {
3: public HttpRoutingDispatcher(HttpConfiguration configuration);
4: public HttpRoutingDispatcher(HttpConfiguration configuration, HttpMessageHandler defaultHandler);
5:
6: protected override Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken);
7: }
ASP.NET Web API消息处理管道不具有一个类似于HttpContext的对象来表示基于当前请求的上下文,但是表示请求消息的HttpRequestMessage对象具有一个通过Properties属性表示的属性字典,我们可以将基于当前上下文的数据或对象添加到当前请求消息的属性字典中。通过对HttpServer的介绍我们知道它会将当前SynchronizationContext和HttpConfiguration添加当前请求消息的属性字典,通过ASP.NET Web API路由系统生成的HttpRouteData或者通过ASP.NET路由系统生成的RouteData转换而成的HttRouteData(针对Web Host寄宿模式)同样以相同的方式保存在当前请求消息中。
保存HttpRouteData对应属性条目的Key为“MS_HttpRouteData”,我们可以通过类型HttpPropertyKeys的静态字段HttpRouteDataKey得到这个Key,也可以直接调用HttpRequestMessage的如下两个扩展方法GetRouteData和SetRouteData进行RouteData的获取和设置。
1: public static class HttpPropertyKeys
2: {
3: //其他成员
4: public static readonly string HttpRouteDataKey;
5: }
6:
7: public static class HttpRequestMessageExtensions
8: {
9: //其他成员
10: public static IHttpRouteData GetRouteData(this HttpRequestMessage request);
11: public static void SetRouteData(this HttpRequestMessage request, IHttpRouteData routeData);
12: }
当HttpRoutingDispatcher的SendAsync方法被执行的时候,它会先判断作为参数的HttpRequestMessage对象的属性字典中的HttpRouteData是否已经存在,如果存在则直接将请求交付给创建时指定的HttpMessageHandler进行处理。如果在通过预定义的Key在请求消息的属性列表中找不到HttpRouteData对象,则直接通过指定的HttpConfiguration的Routes属性得到但前路由表,并将但前请求作为参数调用其GetRouteData方法。如果方法返回一个具体的HttpRouteData对象,则将请求交付给创建时指定的HttpMessageHandler进行后续处理,否则直接返回一个“404, Not Found”响应。
HttpControllerDispatcher
我们从命名可以看出HttpRoutingDispatcher具有两个基本的职能,即“路由(Routing)”和“消息分发(Dispatching)”。对于前者,它会调用当前路由表对请求消息进行解析进而生成用于封装路由数据的HttpRouteData(如果这样的HttpRouteData不存在于当前请求的属性字典中)。对于后者,它会将请求直接分发给在创建时指定的HttpMessageHandler来完成进一步处理。
在默认的情况下(在创建HttpRoutingDispatcher对象的时候在构造函数中没有通过参数具体指定这个HttpMessageHandler)这个从HttpRoutingDispatcher手中接管请求的HttpMessageHandler是一个HttpControllerDispatcher的对象,其成员定义入下所示。HttpControllerDispatcher在整个消息处理管道中显得尤为重要,HttpController的激活、Action方法的执行以及响应消息的生成均是由HttpControllerDispatcher来完成的。
1: public class HttpControllerDispatcher : HttpMessageHandler
2: {
3: public HttpControllerDispatcher(HttpConfiguration configuration);
4: protected override Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken);
5:
6: public HttpConfiguration Configuration { get; }
7: }

当我们将HttpControllerDispatcher引入后,整个消息处理管道具有了如右图所示的结构。从这个结构来看,貌似HttpControllerDispatcher才是整个消息处理管道的最后一个HttpMessageHandler。这种说法没有错,但我们个人还是倾向于将HttpControllerDispatcher视为“隶属于” HttpRoutingDispatcher的“内部”HttpMessageHandler,所以仍将这个“包含” HttpRoutingDispatcher的HttpRoutingDispatcher视为组成消息处理管道的最后一个HttpMessageHandler。除此之外,“N个DelegagingHandler + 1个HttpMessageHander”这样的链式结构也刚好与基于DelegagingHandler的委托链相匹配。对于读者朋友来说,具体倾向于那种说法并不重要,重要的是能够深刻了解整个消息处理管道的真正构成。
实例演示:揭示HttpRoutingDispatcher的路由功能
为了让读者对实现在HttpRoutingDispatcher中的路由功能(即通过调用路由表对请求消息进行匹配解析并生成HttpRouteData,并将其放入请求消息的属性字典)具有更加深刻的影响,我们来进行一个简单的实例演示来揭示其路由功能的存在。
我们在一个空的ASP.NET MVC应用中定义如下一个MyHttpRoutingDispatcher。MyHttpRoutingDispatcher直接继承自HttpRoutingDispatcher,其SendAsync方法的目的在于将受保护的同名方法“转换”成公有方法以方便后续调用。
1: public class MyHttpRoutingDispatcher : HttpRoutingDispatcher
2: {
3: public MyHttpRoutingDispatcher(HttpConfiguration configuration)
4: : base(configuration)
5: { }
6:
7: public new Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
8: {
9: return base.SendAsync(request, cancellationToken);
10: }
11: }
我们创建了一个具有如下定义的HomeController。在默认的Action方法Index中,我们创建了一个HttpConfiguration,并在其路由表中注册了一个URL模板为“wheather/{areaCode}/{days}”的HttpRoute。然后为创建了一个基于HTTP-GET的HttpRequestMessage,其访问地址(“http://www.artech.com/wheather/010/2”)与注册的URL模板相匹配。接下来我们针对这个HttpConfiguration创建了一个MyHttpRoutingDispatcher对象,并将该HttpRequestMessage对象作为参数调用其SendAsync方法。最后我们直接调用HttpRequestMessage对象的扩展方法GetRouteData获取添加到它属性字典中的HttpRouteData对象,并将保存在Values属性中的路由变量的名称和值输出来。
1: public class HomeController : Controller
2: {
3: public void Index()
4: {
5: HttpConfiguration configuration = new HttpConfiguration();
6: configuration.Routes.MapHttpRoute("default", "wheather/{areaCode}/{days}");
7: HttpRequestMessage request = new HttpRequestMessage(HttpMethod.Get, "http://www.artech.com/wheather/010/2");
8: MyHttpRoutingDispatcher dispatcher = new MyHttpRoutingDispatcher(configuration);
9: dispatcher.SendAsync(request, new CancellationToken(false));
10: IHttpRouteData routeData = request.GetRouteData();
11: foreach (var item in routeData.Values)
12: {
13: Response.Write(string.Format("{0}: {1}<br/>", item.Key, item.Value));
14: }
15: }
16: }

该程序运行之后会在浏览器中呈现出如右图所示的输出结果,可以看出我们期望的两个路由变量(areaCode和days)被正常输出,而它们正是在HttpRoutingDispatcher的SendAsync方法被执行的时候生成并添加到请求消息之中的。
缺省路由变量的删除
我们在进行路由注册的时候可以为某个路由变量设置一个默认值,这个默认值可以是一个具体的变量值,也可以是通过RouteParameter具有如下定义的静态只读字段Optional返回的一个RouteParameter对象,我们具有这种默认值的路由变量成为缺省路由变量。
1: public sealed class RouteParameter
2: {
3: public static readonly RouteParameter Optional;
4: }
虽然同是具有默认值的路由变量,但是缺省路由变量具有不同之处:如果请求URL中没有提供对应变量的值,普通具有默认值的路由变量依然会出现在最终HttpRouteData的Values属性中,但是缺省路由变量则不会。实际上缺省路由变量的删除是由HttpRoutingDispatcher实现的。在执行SendAsync方法的时候,如果得到的HttpRouteData(可能是预先添加到HttpRequestMessage的属性字典中,也可以是HttpRoutingDispatcher利用ASP.NET Web API路由系统对请求进行解析获得)的Values属性具有值为RouteParameter. Optional的路由变量,它会被直接剔除出去。
ASP.NET Web API的消息处理管道: HttpRoutingDispatcher的更多相关文章
- ASP.NET Web API的消息处理管道:"龙头"HttpServer
ASP.NET Web API的消息处理管道:"龙头"HttpServer 一般来说,对于构成ASP.NET Web API消息处理管道的所有HttpMessageHandler来 ...
- ASP.NET Web API的消息处理管道: Self Host下的消息处理管道[上篇]
ASP.NET Web API的消息处理管道: Self Host下的消息处理管道[上篇] ASP.NET Web API服务端框架核心是一个独立于具体寄宿环境的消息处理管道,它不关心请求消息来源于何 ...
- ASP.NET Web API 2 消息处理管道
Ø 前言 ASP.NET 的应用程序都会有自己的消息处理管道和生命周期,比如:ASP.NET Web 应用程序(Web Form).ASP.NET MVC,还有本文将讨论的 ASP.NET Web ...
- ASP.NET Web API标准的“管道式”设计
ASP.NET Web API的核心框架是一个消息处理管道,这个管道是一组HttpMessageHandler的有序组合.这是一个双工管道,请求消息从一端流入并依次经过所有HttpMessageHan ...
- Web API之消息处理管道
Web API之消息处理管道 前言 MVC有一套请求处理的机制,当然Web API也有自己的一套消息处理管道,该消息处理管道贯穿始终都是通过HttpMessageHandler来完成.我们知道请求信息 ...
- ASP.NET Web API的安全管道
本篇体验ASP.NET Web API的安全管道.这里的安全管道是指在请求和响应过程中所经历的各个组件或进程,比如有IIS,HttpModule,OWIN,WebAPI,等等.在这个管道中大致分两个阶 ...
- Web APi之消息处理管道(五)
前言 MVC有一套请求处理的机制,当然Web API也有自己的一套消息处理管道,该消息处理管道贯穿始终都是通过HttpMessageHandler来完成.我们知道请求信息存在 RequestMessa ...
- ASP.NET Web API标准的“管道式”设计
详见:http://www.cnblogs.com/artech/p/asp-net-web-api-pipeline.html http://www.codeproject.com/Articles ...
- 目标HttpController在ASP.NET Web API中是如何被激活的:目标HttpController的创建
目标HttpController在ASP.NET Web API中是如何被激活的:目标HttpController的创建 通过上面的介绍我们知道利用HttpControllerSelector可以根据 ...
随机推荐
- ThinkPHP 3.2 开放 cache注缓存,过滤非法字符
打开缓存配置文件 /Application/Common/conf/cache.php源代码如下面: <?php return array( //'配置项'=>'配置值' 'LAYOUT_ ...
- SSH—Struts(三)—跑步者(Action)
如已经描述Struts其基本原理和控制器ActionServlet,根据一个请求通过流ActionServlet之后就要到达Action类中做详细的处理了.ActionServlet通过ActionM ...
- linux虚拟文件系统2
转自:http://rstevens.iteye.com/blog/849413 一.概述 Linux 文件系统是相当复杂的,本文只分析虚拟文件系统的实现,对具体的文件系统不涉及. 即使是虚拟文件系统 ...
- 《自己动手写CPU》写书评获赠书活动结果
<自己动手写CPU>写书评获赠图书的读者有: 京东:8***2.16号哨兵.magicyu.kk6803.jddickyd.杰出的胡兵 亚马逊:徐贺.马先童.jaychen.farmfar ...
- Objective-C系列
我的Objective-C系列文章和坚持写博客的感想 做iOS开发有一段时间了,也有自己上线的App产品,也在坚持着发表技术博客总结自己所学的东西.在写博客的时候虽然博文中不免有错别字,但每句话都 ...
- windows下 composer常见问题及处理
错误一: Warning: This development build of composer is over 30 days old. It is recommend ed to update i ...
- - C#编程大幅提高OUTLOOK的邮件搜索能力!
原文:[原创] - C#编程大幅提高OUTLOOK的邮件搜索能力! 使用OUTLOOK, 你有没有遇到过上图的问题? 多达18419封邮件! 太多了, 每次想找一个邮件都非常耗时, 想办法解决这个问题 ...
- 使用Windows2003创建AD服务器 - 进阶者系列 - 学习者系列文章
Windows 2003的AD功能不是很强,但是还是提供了不错的功能.下面简要介绍下Windows 2003的AD配置说明. 1. 从添加删除Windows组件安装AD功能项 2. 完成安装.这里 ...
- Entity Framework 5 自定义代码生成模板 转
Entity Framework 5 发布有一定时间了,但学习资源确实不多,更何况英语差的我,看英语确实费力,不管怎么样,问题还是解决了,查看很多人写的文章(让我看的想放弃,更想找到答案),都没有到到 ...
- C注意,使用的语言字符串
转载请注明出处! 在C语言没有具体的字符串数据类型,字符串的字符串常量和字符数组的形式. 实际上该字符串是零个或更多字符的字符串.并在整个位模式0NUL字节结束.因此,字符串所包括的字符内部不能出现N ...