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模式下是怎样实现的?请继续往下看。

HttpControllerRoutingHandler

当通过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对象。所以在注册路由的过程是:

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对象,接着利用RoteData对象对应的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管道

Web Host消息处理管道的更多相关文章

  1. Web APi之Web Host消息处理管道(六)

    前言 我们知道Web API本身是无法提供请求-响应的机制,它是通过Web Host以及Self Host的寄宿的宿主方式来提供一个请求-响应的运行环境.二者都是将请求和响应抽象成HttpRespon ...

  2. ASP.NET Web API消息处理管道:Self Host下的消息处理管道[下篇]

    ASP.NET Web API消息处理管道:Self Host下的消息处理管道[下篇] 我们知道ASP.NET Web API借助于HttpSelfHostServer以Self Host模式寄宿于当 ...

  3. 细说Asp.Net Web API消息处理管道(二)

    在细说Asp.Net Web API消息处理管道这篇文章中,通过翻看源码和实例验证的方式,我们知道了Asp.Net Web API消息处理管道的组成类型以及Asp.Net Web API是如何创建消息 ...

  4. ASP.NET Web API的消息处理管道: Self Host下的消息处理管道[上篇]

    ASP.NET Web API的消息处理管道: Self Host下的消息处理管道[上篇] ASP.NET Web API服务端框架核心是一个独立于具体寄宿环境的消息处理管道,它不关心请求消息来源于何 ...

  5. ASP.NET Web API 框架研究 Self Host模式下的消息处理管道

    Self Host模式下的ASP.NET Web API与WCF非常相似,都可以寄宿在任意类型的托管应用程序中,宿主可以是Windows Form .WPF.控制台应用以及Windows Servic ...

  6. ASP.NET Web API 框架研究 Web Host模式下的消息处理管道

    寄宿的作用是开启一个进程为Web API提供一个运行环境以解决持续监听.请求监听和响应回复,即将接收到的请求转换成HttpRequestMessage对象传入管道,并将管道生成并经过处理后的HttpR ...

  7. ASP.NET Web API 框架研究 Web Host模式路由及将请求转出到消息处理管道

    Web Host 模式下的路由本质上还是通过ASP.NET 路由系统来进行路由的,只是通过继承和组合的方式对ASP.NET路由系统的内部的类进行了一些封装,产生自己专用一套类结构,功能逻辑基本都是一样 ...

  8. ASP.NET Web API的消息处理管道: HttpRoutingDispatcher

    ASP.NET Web API的消息处理管道: HttpRoutingDispatcher 认情况下,作为消息处理管道“龙头”的HttpServer的Dispatcher属性返回一个HttpRouti ...

  9. ASP.NET Web API的消息处理管道:"龙头"HttpServer

    ASP.NET Web API的消息处理管道:"龙头"HttpServer 一般来说,对于构成ASP.NET Web API消息处理管道的所有HttpMessageHandler来 ...

随机推荐

  1. linux sort,uniq,cut,wc命令详解 (转)

    sort sort 命令对 File 参数指定的文件中的行排序,并将结果写到标准输出.如果 File 参数指定多个文件,那么 sort 命令将这些文件连接起来,并当作一个文件进行排序. sort语法 ...

  2. 开源 自由 java CMS - FreeCMS1.8 网上申报

    项目地址:http://code.google.com/p/freecms/ 在线申报 1. 转交申报 用户能够把申报转交给其它人办理,系统会记录此申报的转交记录. 注意:同一时候仅仅能转交一个申报. ...

  3. React Native环境配置

    React Native环境配置 史上最全Windows版本搭建安装React Native环境配置 配置过React Native 环境的都知道,在Windows React Native环境配置有 ...

  4. Android AlarmManager报警的实现

    什么是AlarmManager? AlarmManager它是Android经常使用的系统-Level提醒服务,我们指定为广播中的特定时间Intent. 我们设定一个时间,然后在该时间到来时.Alar ...

  5. jq分页插件

    jq分页插件 http://www.zhangxinxu.com/jq/pagination_zh/ html --------------- <tbody id="hiddenres ...

  6. Hosting WCF Service

    之前在博客几个实例DemoWCF服务寄宿到控制到应用程序中,这篇来总结一下,经常使用的几种宿主的方式. 1.Self-Hosting 一个WCF服务可以寄宿在控制台应用程序或者WinForms app ...

  7. ./startup.sh: Permission denied

    今天在Linux上部署项目,之前报过这个错误,通过下面方式攻克了.如今发出来备份一下: LINUX权限-bash: ./startup.sh: Permission denied 运行./startu ...

  8. 【C语言探索之旅】 第一部分第九课:函数

    内容简介 1.课程大纲 2.第一部分第九课:函数 3.第一部分第十课预告: 练习题+习作 课程大纲 我们的课程分为四大部分,每一个部分结束后都会有练习题,并会公布答案.还会带大家用C语言编写三个游戏. ...

  9. 10gocm-&gt;session5-&gt;数据库管理实验-&gt;GC资源管理器的资源消耗组介绍

    <GC资源管理器>  官方文件:administrator's Guide->24 Using the Database Resource Manager 用法:在实际生产环境中使用 ...

  10. 【Android进阶】Application对象的详解

    1:Application是什么? Application和Activity,Service一样,是android框架的一个系统组件,当android程序启动时系统会创建一个 application对 ...