zoukankan      html  css  js  c++  java
  • Web Host消息处理管道

    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管道

     

  • 相关阅读:
    Java对象的生命周期与作用域的讨论(转)
    [置顶] Oracle学习路线与方法
    Java实现 蓝桥杯 算法训练 未名湖边的烦恼
    Java实现 蓝桥杯 算法训练 未名湖边的烦恼
    Java实现 蓝桥杯 算法训练 未名湖边的烦恼
    Java实现 蓝桥杯 算法训练 最大的算式
    Java实现 蓝桥杯 算法训练 最大的算式
    Java实现 蓝桥杯 算法训练 最大的算式
    Java实现 蓝桥杯 算法训练 最大的算式
    Java实现 蓝桥杯 算法训练 最大的算式
  • 原文地址:https://www.cnblogs.com/Leo_wl/p/4836948.html
Copyright © 2011-2022 走看看