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 ...
随机推荐
- asp.net 页面上的点击事件
asp.net 页面上 服务器端控件Button 有两个click事件如 <asp:Button ID="Button1" runat="server" ...
- 6_PHP AJAX MYSQL
XAMPP套装软件: 包含Apache.MySQL.PHP等多个开源软件的集合. https://www.apachefriends.org/zh_cn/index.html 监听完整相应消息: Wi ...
- swiper的初步使用
1.引入文件,顺序引入(此处基于jquery,且版本至少1.7以上) <link rel="stylesheet" href="path/to/swiper-3.4 ...
- Python之路第一课Day9--随堂笔记之一(堡垒机实例以及数据库操作)未完待续....
一.堡垒机前戏 开发堡垒机之前,先来学习Python的paramiko模块,该模块机遇SSH用于连接远程服务器并执行相关操作 SSHClient 用于连接远程服务器并执行基本命令 基于用户名密码连接: ...
- Tomcat 配置续
为了便于tomcat升级 不用频繁重新修改相关配置文件 不用重新部署原有项目 新建目录将tomcat安装目录中的conf,log,webapp,work文件夹复制到里面,然后将系统变量里的CATALI ...
- #iOS问题记录# 关于UITableViewcel的分割线去掉问题
十分清楚的记得以前在使用的时候,通过[_mTableView setSeparatorStyle:UITableViewCellSeparatorStyleNone];这一句话来达到效果的. 这次怎么 ...
- 谢欣伦 - OpenDev原创教程 - 蓝牙设备查找类CxBthRemoteDeviceFind
这是一个精练的蓝牙设备查找类,类名.函数名和变量名均采用匈牙利命名法.小写的x代表我的姓氏首字母(谢欣伦),个人习惯而已,如有雷同,纯属巧合. CxBthRemoteDeviceFind的使用如下: ...
- 在VisualStadio2015上使用EF6.0建立MySql数据库
1.新建工程 2.建立类的文件夹DAL 3.建立相关类 [Student类] using System;using System.Collections.Generic;using System.Li ...
- 初学java之12 泛型编程的个人理解总结
首先,强调一个观点: 对于我这样的初学者,一定要站在虚拟机和编译器的角度来分析java 语言的种种特性,泛型也不例外.(我认为这个一条正确的学习经验) 写这篇文章起源于最近在学java,有一天在路上和 ...
- SQL Server2014 哈希索引原理
SQL Server2014 哈希索引原理 翻译自:http://www.sqlservercentral.com/blogs/sql-and-sql-only/2015/09/08/hekaton- ...