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在后续原理中进行讲解。。。。。。







本文转自Jeffcky博客园博客,原文链接:http://www.cnblogs.com/CreateMyself/p/4834785.html,如需转载请自行联系原作者
目录
相关文章
|
5月前
|
数据采集 安全 大数据
Dataphin 5.1:API数据源及管道组件升级,适配多样化认证的API
为提升API数据交互安全性,Dataphin 5.1推出两种新认证方式:基于OAuth 2.0的动态授权与请求签名认证。前者通过短期Access Token确保安全,后者对关键参数加密签名保障数据完整性。功能支持API数据源OAuth 2.0认证和自定义签名配置,未来还将拓展更灵活的认证方式以满足多样化需求。
171 14
|
12月前
|
Java API 数据库
构建RESTful API已经成为现代Web开发的标准做法之一。Spring Boot框架因其简洁的配置、快速的启动特性及丰富的功能集而备受开发者青睐。
【10月更文挑战第11天】本文介绍如何使用Spring Boot构建在线图书管理系统的RESTful API。通过创建Spring Boot项目,定义`Book`实体类、`BookRepository`接口和`BookService`服务类,最后实现`BookController`控制器来处理HTTP请求,展示了从基础环境搭建到API测试的完整过程。
161 4
|
6月前
|
人工智能 搜索推荐 IDE
突破网页数据集获取难题:Web Unlocker API 助力 AI 训练与微调数据集全方位解决方案
本文介绍了Web Unlocker API、Web-Scraper和SERP API三大工具,助力解决AI训练与微调数据集获取难题。Web Unlocker API通过智能代理和CAPTCHA绕过技术,高效解锁高防护网站数据;Web-Scraper支持动态内容加载,精准抓取复杂网页信息;SERP API专注搜索引擎结果页数据抓取,适用于SEO分析与市场研究。这些工具大幅降低数据获取成本,提供合规保障,特别适合中小企业使用。粉丝专属体验入口提供2刀额度,助您轻松上手!
304 2
|
6月前
|
人工智能 运维 安全
网络安全公司推荐:F5荣膺IDC全球Web应用与API防护领导者
网络安全公司推荐:F5荣膺IDC全球Web应用与API防护领导者
129 4
|
9月前
|
人工智能 前端开发 API
Gemini Coder:基于 Google Gemini API 的开源 Web 应用生成工具,支持实时编辑和预览
Gemini Coder 是一款基于 Google Gemini API 的 AI 应用生成工具,支持通过文本描述快速生成代码,并提供实时代码编辑和预览功能,简化开发流程。
475 38
Gemini Coder:基于 Google Gemini API 的开源 Web 应用生成工具,支持实时编辑和预览
|
7月前
|
XML JSON API
Understanding RESTful API and Web Services: Key Differences and Use Cases
在现代软件开发中,RESTful API和Web服务均用于实现系统间通信,但各有特点。RESTful API遵循REST原则,主要使用HTTP/HTTPS协议,数据格式多为JSON或XML,适用于无状态通信;而Web服务包括SOAP和REST,常用于基于网络的API,采用标准化方法如WSDL或OpenAPI。理解两者区别有助于选择适合应用需求的解决方案,构建高效、可扩展的应用程序。
|
7月前
|
机器学习/深度学习 开发框架 API
Python 高级编程与实战:深入理解 Web 开发与 API 设计
在前几篇文章中,我们探讨了 Python 的基础语法、面向对象编程、函数式编程、元编程、性能优化、调试技巧以及数据科学和机器学习。本文将深入探讨 Python 在 Web 开发和 API 设计中的应用,并通过实战项目帮助你掌握这些技术。
|
10月前
|
Kubernetes 安全 Devops
有效抵御网络应用及API威胁,聊聊F5 BIG-IP Next Web应用防火墙
有效抵御网络应用及API威胁,聊聊F5 BIG-IP Next Web应用防火墙
258 10
有效抵御网络应用及API威胁,聊聊F5 BIG-IP Next Web应用防火墙
|
11月前
|
前端开发 API 开发者
Python Web开发者必看!AJAX、Fetch API实战技巧,让前后端交互如丝般顺滑!
在Web开发中,前后端的高效交互是提升用户体验的关键。本文通过一个基于Flask框架的博客系统实战案例,详细介绍了如何使用AJAX和Fetch API实现不刷新页面查看评论的功能。从后端路由设置到前端请求处理,全面展示了这两种技术的应用技巧,帮助Python Web开发者提升项目质量和开发效率。
223 1
|
11月前
|
JSON API 数据格式
如何使用Python和Flask构建一个简单的RESTful API。Flask是一个轻量级的Web框架
本文介绍了如何使用Python和Flask构建一个简单的RESTful API。Flask是一个轻量级的Web框架,适合小型项目和微服务。文章从环境准备、创建基本Flask应用、定义资源和路由、请求和响应处理、错误处理等方面进行了详细说明,并提供了示例代码。通过这些步骤,读者可以快速上手构建自己的RESTful API。
605 2

热门文章

最新文章