Web APi之Web Host消息处理管道(六)
前言
我们知道Web API本身是无法提供请求-响应的机制,它是通过Web Host以及Self Host的寄宿的宿主方式来提供一个请求-响应的运行环境。二者都是将请求和响应抽象成HttpResponseMessage和HttpRequesMessage对象,并将请求HttpRequestMessage传入到HttpMessageHandler进行处理最终将响应通过HttpResponseMessage逆向通过HttpMessageHandler返回到客户端,但是在其过程中,此二者在管道中的机制是不一样的,由于在最新Web API中是以Web Host寄宿实现,所以仅本节仅讨论Web Host寄宿的实现。
Web Host
Web API采用Web Host寄宿模式,其路由系统最终还是通过ASP.NET的路由系统来实现,也就是说其本质是将ASP.NET应用程序作为Web API的宿主,利用ASP.NET自身的路由系统并结合IIS来实现去持续监听以及请求和响应的问题。
既然Web Host寄宿是利用ASP.NET的路由系统实现,那么我们首先就得了解下ASP.NET的路由系统,ASP.NET的路由是利用UrlRoutingModel中的HttpModel来完成,并通过HttpApplication中的PostResloveRequesCache事件对其请求进行拦截,并借助注册的路由将请求的URL进行解析获得路由数据对象RouteData,UrlRoutingModel最终从匹配对象Route对象中获取对应的HttpHandler并映射给当前上下文HttpContext,紧接着上下文HttpContext获取请求并进行响应。
上述听起来似乎有点拗口并且不太能让人理解,我们首先来了解下ASP.NET的请求管道,当一个请求过来时首先会经过扩展名来进行相应的处理,如果是静态文件则直接返回到客户端,若是动态文件如扩展名为.aspx,则将交给aspnet.isapi.dll来进行处理,然后就是创建一个ASP.NET运行环境HttpRuntime,在创建运行环境的同时首先创建一个HttpWorkerRquest对象,这个对象则保存着请求的报文信息,接着借助HttpWorkerRequest对象创建上下文 HttpContext (包含着HttpResponse和HttpRequest以及HttpSessionState等)接下来就是通过ApplicationFactory工厂创建一个上述所说的 HttpApplication 对象,此对象为管道事件的核心对象,然后调用ProcessRequest方法将上下文HttpContext传入其中,最终通过HttpApplication来执行19个管道事件,在前八个事件利用 HttpModel 进行相关的验证、授权等,在第八个事件则创建页面类对象同时实现IHttpHandler接口创建一个我们上述所说的 HttpHandler ,后面大概就是创建页面控件树以及执行页面对象的页面生命周期等。
通过上述叙述知,Web API利用Web Host作为寄宿则利用UrlRoutingModel来动态映射给HttpContext中的HttpHandler是实现管道集成的核心,它会将ASP.NET中的HttpRequest对象表示的请求转换成HttpRequestMessage对象并传入到消息管道中,并将输出的HttpResponseMessage写入到HttpResponse中并最终进行响应输出。现在最主要的问题是这个HttpHandler在Web Host模式下是怎样实现的?请继续往下看。
HttpControllerRouteHandler
当通过Web API的配置文件通过模板以及约束等注册一个HttpRoute路由对象到路由集合中时也就是将其注册到路由表中(因为路由表中的属性Routes存着注册的路由的路由集合),首先会创建一个HostedHttpRoute对象,我们看看该对象的定义:
其中最重要的是OriginalRoute属性,照定义来看就仅仅是创建了这个对象而已,确确实实是这样,因为该对象仅仅是起一个过渡作用,因为真正创建的对象是HttpWebRoute的Route对象,通过查看其构造函数可知,如下:
public HostedHttpRoute(string uriTemplate, IDictionary<string, object> defaults, IDictionary<string, object> constraints, IDictionary<string, object> dataTokens, HttpMessageHandler handler)
{
RouteValueDictionary dictionary;
RouteValueDictionary dictionary2;
RouteValueDictionary dictionary3;
base..ctor();
dictionary = (defaults != null) ? new RouteValueDictionary(defaults) : null;
dictionary2 = (constraints != null) ? new RouteValueDictionary(constraints) : null;
dictionary3 = (dataTokens != null) ? new RouteValueDictionary(dataTokens) : null;
this.OriginalRoute = new HttpWebRoute(uriTemplate, dictionary, dictionary2, dictionary3, HttpControllerRouteHandler.Instance, this);
this.Handler = handler;
return;
}
如上红色标记,此时将属性OriginalRoute作为HttpWebRoute对象的引用存在HostedHttpRoute中并返回一个Route对象。
那么上述所说的RouteData是什么时候生成呢?
我们再来看看这个Route对象的定义:
当请求过来时请求URL会与注册的路由(Route)进行匹配,若匹配成功,由上知,此时同时会通过GetRouteData方法生成一个 RouteData 对象,我们同时看看该RouteData的定义:
public class RouteData
{
// Fields
private RouteValueDictionary _dataTokens;
private IRouteHandler _routeHandler;
private RouteValueDictionary _values; // Methods
public RouteData();
public RouteData(RouteBase route, IRouteHandler routeHandler);
public string GetRequiredString(string valueName); // Properties
public RouteValueDictionary DataTokens { get; }
public RouteBase Route { get; set; }
public IRouteHandler RouteHandler { get; set; }
public RouteValueDictionary Values { get; }
}
此对象中有一个匹配路由Route的引用属性,也就是当前匹配成功的Route对象并且还有返回值为IRouteHandler的属性RouteHandler。
所以在注册路由的过程是:
HttpRoute-------------->HostedHttpRoute-------------->HttpWebRoute------------->Route
在HttpWebRoute继承自Route类中有一个属性RouteHandler如下:
public IRouteHandler RouteHandler { [CompilerGenerated] get; [CompilerGenerated] set; }
我们通过如下HttpControllerRouteHandler的定义知,上述RouteHandler就是一个HttpControllerRouteHandler对象,因为HttpControllerRouteHandler实现了接口IRouteHandler,如下:
public class HttpControllerRouteHandler : IRouteHandler
{
// Fields
private static readonly Lazy<HttpControllerRouteHandler> _instance;
[CompilerGenerated]
private static Func<HttpControllerRouteHandler> CS$<>9__CachedAnonymousMethodDelegate1; // Methods
static HttpControllerRouteHandler();
protected HttpControllerRouteHandler();
[CompilerGenerated]
private static HttpControllerRouteHandler <.cctor>b__0();
protected virtual IHttpHandler GetHttpHandler(RequestContext requestContext);
IHttpHandler IRouteHandler.GetHttpHandler(RequestContext requestContext); // Properties
public static HttpControllerRouteHandler Instance { get; }
}
注意上述标记,通过GetHttpHandler方法知,在ASP.NET路由中的HttpHandler就是由HttpControllerRouteHandler对象提供的,同时我们看下该方法的定义:
protected virtual IHttpHandler GetHttpHandler(RequestContext requestContext)
{
return new HttpControllerHandler(requestContext.RouteData);
}
看见这个方法的返回值没,又涉及到一个对象,其实通过HttpControllerRouteHandler中的方法获得的HttpHandler其实是一个HttpControllerHandler对象,而整个消息处理管道则是有它来创建的。请继续往下看!
HttpControllerHandler
上面说过此对象是Web Host寄宿模式下的整个管道的执行者,下面我们就来看看这个类的定义(操蛋,太长了还是就看下这个类的继承,再叙述其他的再给代码):
public class HttpControllerHandler : HttpTaskAsyncHandler
{
}
再看下其父类的定义:
public abstract class HttpTaskAsyncHandler : IHttpAsyncHandler, IHttpHandler
{
// Methods
protected HttpTaskAsyncHandler();
[EditorBrowsable(EditorBrowsableState.Never)]
public virtual void ProcessRequest(HttpContext context);
public abstract Task ProcessRequestAsync(HttpContext context);
IAsyncResult IHttpAsyncHandler.BeginProcessRequest(HttpContext context, AsyncCallback cb, object extraData);
void IHttpAsyncHandler.EndProcessRequest(IAsyncResult result); // Properties
public virtual bool IsReusable { get; }
}
简单叙述下,HttpRouteHandler是HttpTaskAsyncHadler的子类,并且其父类为实现了IHttpAsync和IHttpHandler接口的抽象类。最主要的是HttpTaskAsyncHandler调用了实现IHttpAsyncHandler接口的BeginProcessRequest方法,并返回一个IAsyncResult,而EndProcessRequest方法则用来执行了返回值为IAsyncResult的BeginProcessRequest方法。
我们再来看看HttpRouteHandler的一个构造函数:
public HttpControllerHandler(RouteData routeData, HttpMessageHandler handler);
该构造函数的第一个参数就是根据路由解析得到的路由数据,第二个参数就是管道中的处理程序,实质上就是第一个HttpMessageHandler即管道头(HttpServer)。
下面我们总结下在ASP.NET路由系统中HttpControllerHandler被创建的整个过程。请看!
总结
当进入ASP.NET请求管道中时,在HttpModel中通过事件对其请求进行拦截后,然后利用UrlRoutingModel中注册的路由对象对当前请求的URL进行匹配,若匹配通过由对应匹配的路由解析并生成一个RouteData对象,当然这个Route对象就是HttpWebRoute对象,接着利用RouteData对象对应的Route来获得RouteHandler,这个RouteHandler就是HttpControllerRouteHandler,接着利用UrlRoutingModel中得到的RouteData和当前上下文HttpContext生成一个请求上下文对象,再以该请求上下文对象为对象调用HttpControllerRouteHandler上的GetHttpHandler方法获得HttpHandler(返回的是HttpControllerHandler),并将HttpHandler映射到当前上下文HttpContext中,然后调用HttpControllerHandler上继承自IHttpAsyncHandler上的BeginProcessRequest方法开始进入Web API管道。
下面我们实现IHttpModel接口并对照上述叙述进行编码,如下:
public class WebHost : IHttpModule
{ public void Dispose()
{
throw new NotImplementedException();
} public void Init(HttpApplication context)
{
context.PostResolveRequestCache += context_PostResolveRequestCache;
} void context_PostResolveRequestCache(object sender, EventArgs e)
{
var app = sender as HttpApplication;
var contextWrapper = new HttpContextWrapper(app.Context);
var routeData = RouteTable.Routes.GetRouteData(contextWrapper);
var requestContext = new RequestContext(contextWrapper, routeData);
var httpHandler = routeData.RouteHandler.GetHttpHandler(requestContext);
var httpAsyncHandler = httpHandler as IHttpAsyncHandler;
httpAsyncHandler.BeginProcessRequest(app.Context, null, null);
}
}
总结
下面就Web API中Web Host寄宿模式下的消息处理管道给出整体示意图:来自【Web Host管道】
温馨提示 :有关上述图片HttpControllerDispatcher在后续原理中进行讲解。。。。。。
Web APi之Web Host消息处理管道(六)的更多相关文章
- ASP.NET Web API实践系列05,消息处理管道
ASP.NET Web API的消息处理管道可以理解为请求到达Controller之前.Controller返回响应之后的处理机制.之所以需要了解消息处理管道,是因为我们可以借助它来实现对请求和响应的 ...
- Web Host消息处理管道
Web Host消息处理管道 前言 我们知道Web API本身是无法提供请求-响应的机制,它是通过Web Host以及Self Host的寄宿的宿主方式来提供一个请求-响应的运行环境.二者都是将请求和 ...
- ASP.NET Web API WebHost宿主环境中管道、路由
ASP.NET Web API WebHost宿主环境中管道.路由 前言 上篇中说到ASP.NET Web API框架在SelfHost环境中管道.路由的一个形态,本篇就来说明一下在WebHost环境 ...
- ASP.NET Web API Selfhost宿主环境中管道、路由
ASP.NET Web API Selfhost宿主环境中管道.路由 前言 前面的几个篇幅对Web API中的路由和管道进行了简单的介绍并没有详细的去说明一些什么,然而ASP.NET Web API这 ...
- Web API学习——Web API 强势入门指南
Web API是一个比较宽泛的概念.这里我们提到Web API特指ASP.NET Web API. 这篇文章中我们主要介绍Web API的主要功能以及与其他同类型框架的对比,最后通过一些相对复杂的实例 ...
- 返璞归真 asp.net mvc (11) - asp.net mvc 4.0 新特性之自宿主 Web API, 在 WebForm 中提供 Web API, 通过 Web API 上传文件, .net 4.5 带来的更方便的异步操作
原文:返璞归真 asp.net mvc (11) - asp.net mvc 4.0 新特性之自宿主 Web API, 在 WebForm 中提供 Web API, 通过 Web API 上传文件, ...
- http服务 WCF、Web API、Web service、WCF REST之间的区别
http服务 WCF.Web API.Web service.WCF REST之间的区别 在.net平台下,有大量的技术让你创建一个HTTP服务,像Web Service,WCF,现在又出了Web ...
- NET Web API和Web API Client Gen使Angular 2应用程序
使用ASP.NET Web API和Web API Client Gen使Angular 2应用程序的开发更加高效 本文介绍“ 为ASP.NET Web API生成TypeScript客户端API ” ...
- Web API和Web Service
首先,Web API是由Web Service演变而来,它们两者关系就是所有Web Service都是API,但并非所有API都是Web Service.其次,两者都有利于信息的传输,但Web API ...
随机推荐
- [RxJava^Android]项目经验分享 --- 递归实现
介绍一下业务逻辑:获取接口数据,根据接口内容判断是否需要继续获取数据. 本文使用递归思路,通过RxJava来实现此功能,获取数据的Observable直接用模拟的Observable.just()替代 ...
- CF-补题1
CF-补题1 1.CodeForces 735C 题意:n个人淘汰赛,两个人可以比赛的条件是:两人打过的场数之差绝对值<2.求冠军最多可以打多少场. 总结:看了题解,转换一下思路.求n个 ...
- PHP常见的低级错误
写代码的时候,最讨厌的莫过于因为粗心而范的低级错误了,下面这些,你们是不是也经常犯呢? 1.标点符号缺失,诸如:“$”(美元符),“,”(逗号),“;”(分号),"->"(单 ...
- iOS开发之单元测试
开始之前 本文侧重讲述如何在iOS程序的开发过程中使用单元测试.使用Xcode自带的OCUnit作为测试框架. 一.单元测试概述 单元测试作为敏捷开发实践的组成之一,其目的是提高软件开发的效率,维持代 ...
- Linux OpenVPN 服务端吊销(revoke)客户端证书
(转自:https://www.xiaohui.com/dev/server/20070904-revoke-openvpn-client.htm) OpenVPN 服务器与 VPN 客户端之间的身份 ...
- VMware创建Linux虚拟机并安装CentOS(三)
选择“创建自定义布局”手动给Linux指定系统分区.交换分区,鼠标单击“下一步”按钮继续. 首先创建交Swap分区,鼠标单击“创建”按钮,在弹出的“生成存储”对话框中,生成分区选择“标准分区”:鼠标单 ...
- 站内全文检索服务来了,Xungle提供免费全文检索服务
免费站内全文检索服务来了,是的,你没听错.全文检索相信大家已经不太陌生,主流检索服务有sphinx.xunsearch等,但这些都受服务器限制,对于中小站长尤其是没有服务器实现就困难了,随着数据量的增 ...
- iOS 从某个页面返回然后刷新当前页面
-------->不说废话 在返回页面实现下面方法: - (void)navigationController:(UINavigationController*)navigationContro ...
- MySQL修改root密码的多种方法
不知道在cmd模式下是不是区分大小写,我大写成功了,小写没成功,不知是我拼写的错误,还是区分大小写!!?? 方法1: 用SET PASSWORD命令 mysql -u root mysql> S ...
- 欢迎进入MyKTV前后台点歌系统展示
一个项目,一分收获:一个项目,一些资源.Ktv项目也是一样的,所以我想分享我的收获,让你们获得你需要的资源. 一. 那MyKTV点歌系统具体的功能有哪些呢?我们就来看看吧! 1.MyKTV前台功能: ...