ASP.NET管线与应用程序生命周期

ASP.NET管线与应用程序生命周期

8.1节介绍了IIS的系统架构和HTTP请求处理的总体流程,从中可以知道每个ASP.NET网站都对应着一个Web应用程序,此Web应用程序可以响应HTTP请求,为用户提供所需的信息。那么,ASP.NET应用程序具体是如何响应HTTP请求的?包括哪些具体的处理流程?这涉及到ASP.NET应用程序的生命周期问题。

8.2.1 ASP.NET应用程序生命周期*

本节以IIS 6为例分步介绍ASP.NET应用程序处理HTTP请求的处理流程。IIS 7的处理过程与IIS 6相比有些小变化,但总体上是一致的。

1 浏览器发出访问某ASP.NET网页的HTTP请求

假设这个请求是针对此网页所属的ASP.NET应用程序的第一次请求。

当此请求到达Web服务器时,由HTTP.SYS负责接收,根据此请求的URL,HTTP.SYS将其传递给此ASP.NET应用程序所对应的应用程序池,由在此应用程序池中运行的工作者进程负责处理请求[1]

工作者进程接收到这个请求之后,装载专用于处理ASP.NET页面的一个ISAPI扩展“aspnet_isapi.dll”,并将HTTP请求传给它。

工作者进程加载完aspnet_isapi.dll后,由aspnet_isapi.dll负责加载ASP.NET应用程序的运行环境――CLR[2]。 

工作者进程工作于非托管环境(指Windows操作系统本身)之中,而.NET中的对象则工作于托管环境(指CLR)之中,aspnet_isapi.dll起到了一个沟通两者的桥梁作用,将收到的HTTP请求(由非托管环境传来)转发给相应.NET对象(处于托管环境中)处理。

2 创建ApplicationManager对象和应用程序域

加载CLR之后,由ApplicationManager类负责创建一个应用程序域。每个ASP.NET应用程序都运行于自己的应用程序域中,由唯一的应用程序标识符标识。

每个应用程序域都对应着一个ApplicationManager类的实例,由它来负责管理运行在域中的ASP.NET应用程序(比如启动和停止一个ASP.NET应用程序,在指定的ASP.NET应用程序中创建对象等等)。

3 创建HostingEnvironment对象

在为ASP.NET应用程序创建应用程序域的同时,会创建一个HostingEnvironment对象,此对象提供了ASP.NET应用程序的一些管理信息(比如ASP.NET应用程序的标识,对应的虚拟目录和物理目录),并提供了一些附加的功能(比如在应用程序域中注册一个对象,模拟特定的用户等等)。

4为每个请求创建 ASP.NET 核心对象

当应用程序域创建完成之后,一个ISAPIRuntime对象被创建,并自动调用它的ProcessRequest()方法。在此方法中,ISAPIRuntime对象根据传入的HTTP请求创建一个HttpWorkerRequest对象,此对象以面向对象的方式包装了HTTP请求的各种信息(这就是说,原始的HTTP请求信息被封装为HttpWorkerRequest对象)。然后,调用ISAPIRuntime对象的StartProcessing()方法启动整个HTTP请求处理过程(此即“HTTP管线:HTTP Pipeline),在这个处理过程的开端,一个HttpRuntime类型的对象被创建,前面创建好的HttpWorkerRequest对象作为方法参数被传送给此HttpRuntime对象的ProcessRequest()方法。

在HttpRuntime类的ProcessRequest()方法中完成了一些非常重要的工作,其中与Web软件工程师关系最紧密的是:

HttpRuntime类的ProcessRequest()方法根据HttpWorkerRequest对象中所提供的HTTP请求信息,创建了一个HttpContext对象。

HttpContext对象之所以重要,是因为此对象包容了另两个在ASP.NET编程中非常常见的对象:HttpResponse和HttpRequest

HttpRequest对象中的信息来自于原始的HTTP请求,比如它的Url属性就代表了原始HTTP请求信息中的URL。

而HttpResponse对象则拥有一些属性和方法,用于生成要返回给浏览器的信息。

Page类提供了相应的属性来引用这两个对象,因此在ASP.NET网页中可以直接使用“Requset”和“Response”属性来访问这两个对象。例如:

public partial class _Default : System.Web.UI.Page

{

protected void Page_Load(object sender, EventArgs e)

{

Response.Write(Request.Url);

}

}

Page类的Context属性引用HttpContext对象,因此,上述代码也可以改写为以下形式:

public partial class _Default : System.Web.UI.Page

{

protected void Page_Load(object sender, EventArgs e)

{

this.Context.Response.Write(this.Context.Request.Url);

}

}

关于HttpContext、HttpResponse和HttpRequest这三个对象,必须掌握以下的要点:

l  HttpContext对象包容HttpResponse和HttpRequest这两个对象,可以从HttpRequest对象获取HTTP请求的相关信息,而要向浏览器输出的内容可以通过调用HttpResponse的方法实现。

l  针对每个HTTP请求,ASP.NET都会创建一个HttpContext对象,在整个HTTP处理过程中,此对象都是可以访问的。

5 分配一个HttpApplication 对象用于处理请求

HttpRuntime类的ProcessRequest()方法除了创建HttpContext对象之外,还完成了另一个很重要的工作——向HttpApplicationFactory类的一个实例[3]申请分配一个HttpApplication 对象用于管理整个HTTP请求处理管线中的各种事件。

HttpApplicationFactory对象负责管理一个HttpApplication对象池[4],当有HTTP请求到来时,如果池中还有可用的 HttpApplication对象,就直接分配此对象用于处理HTTP请求,否则,创建一个新的HttpApplication对象。

6 HttpApplication对象启动HTTP管线

HttpApplication对象负责装配出整个“HTTP请求处理管线(HTTP Pipeline)”,可以将“HTTP请求处理管线”与现代工厂中的“生产流水线”做个类比。前面步骤中创建好的HttpContext对象就是这个生产流水线要加工的“产品”,当它流经“生产流水线”的不同部分时,将被进行特定的加工和处理过程。

这些特定的“加工和处理过程”是怎样进行的?

简单地说,HttpContext对象经过“生产流水线”的不同部分时,HttpApplication对象会先后激发出一连串的事件[5]。一种特定的组件——HTTP模块(HTTP Module)可以响应这些事件,在此事件响应代码中可以对HttpContext对象进行“加工和处理”,从这个意义上说,HTTP模块可以看成是“生产流水线”中的工人。HTTP模块其实就是前面所介绍过的“ISAPI筛选器”。

HTTP模块对象是在HttpApplication对象的InitModules()方法[6]中被创建的,我们一般在HTTP模块对象Init()方法[7]中书写代码使其可以响应HttpApplication对象所激发的特定事件。

ASP.NET提供了一些预定义的HTTP模块响应特定的事件,Web软件工程师也可以编写自己的HTTP模块并将其插入到“HTTP请求处理管线”中[8]

在流水线的中部(处理完了相关的事件),HttpContext对象被最终的Page对象所接收(这就是为何可以在ASP.NET页面中通过Page类定义的Context属性访问HttpContext对象的原因)。

每个被访问的ASP.NET页面都会被转换为一个“派生自Page类的页面类

注意:Page类实现了IHttpHandler接口,此接口定义了一个ProcessRequest()方法。

ASP.NET页面类生成以后被自动编译为程序集,然后其ProcessRequest()方法被自动调用(因为Page类实现了IHttpHandler接口,所以肯定有此方法)。在此方法中,Web软件工程师编写的代码被执行(如果有的话)。ProcessRequest()方法的执行结果再次被HttpContext对象所承载,控制又转回到“HTTP请求处理流水线”中,HttpApplication对象继续激发后继的事件。这时,如果还有特定的HTTP模块响应这些事件,则它们会被自动调用。

HttpContext对象带着最后的处理结果来到了“HTTP请求处理管线”的未端,其信息被取出来,再次以aspnet_isapi.dll为桥梁传送给工作者进程。工作者进程再将HTTP请求的处理结果转给HTTP.SYS,由它负责将结果返回给浏览器。

根据前面的介绍,可以将整个Http管线分成三段:预处理阶段à处理阶段à后处理阶段(图8‑14)。

图 8‑14 HTTP管线的三个阶段

如图 8‑14所示,HTTP管线的预处理和后处理阶段主要由多个HTTP模块参与,通过事件来驱动,这两个阶段完成的工作主要是对HttpContext对象的各种属性进行修改。

对HTTP请求的处理过程最终是由一个实现IHttpHandler接口的对象在“处理阶段”完成的。每一个ASP.NET网页生成的页面类都实现了此接口。创建出合适的HTTP请求处理对象的工作由PageHandlerFactory对象[9]负责完成。

由此可见,实现了IHttpHandler接口的对象负责处理HTTP请求,这就是它被称为“Handler(处理程序)”的原因。

除了最常见的ASP.NET网页之外,Web软件工程师还可以创建自己的实现了IHttpHandler接口的对象,并将其插入到HTTP管线中用于处理HTTP请求。

当HTTP请求处理完毕,相关的对象被释放,但创建的应用程序域,以及HttpApplication等对象仍然存活,以响应下一次HTTP请求。

7 ASP.NET应用程序生命周期小结

本节中介绍了ASP.NET应用程序的生命周期,这是一个相当复杂的过程,也许用以下通俗的类比更容易理解:

l  “HTTP请求处理管线”就是一条现代工厂中的“生产流水线”,HttpContext对象就是这条流水线上要加工的产品。

l  HttpHandler(HTTP处理程序)对象是整个“产品生产线”的核心,由它负责将产品装配成形。

l  HttpModule(HTTP模块)相当于“生产线”上的辅助工人,他们对产品(HttpContext对象)进行“预处理”(为装配产品作准备)和“后处理”(为产品出厂作准备,比如贴商标)。

l  HttpApplication对象是整个“生产线”的“领导” ,他负责给“生产线”分配工人(初始化并装载所有注册的HttpModule),然后会激发一系列的事件(被称为“ASP.NET应用程序事件”),特定的HttpModule负责响应特定的事件。


[1] 如果工作者进程不存在,则IIS监控程序WAS会创建一个,否则,复用已有的工作者进程。

[2] IIS 7集成模式下,由于CLR是预加载的,所以这一步就不需要了。

[3] “类的实例”与“类的对象”含义等同,都是指以类为模板创建出来的对象。

[4] 对象池(object pool)是面向对象软件系统常见的一种对象组织方式,可以将其看成是一个对象容器。对象池中放有事先创建好的多个对象。当外界需要某个对象时,可以直接从池中取出一个现成的对象使用,这就避免了频繁创建对象所带来的性能损失。

[5] HttpApplication定义了相当多的事件,完整的事件清单请查看MSDN。

[6] 此方法会在获取HttpApplication对象时被自动调用。

[7] 所有HTTP模块都要实现IHttpModule接口,Init()方法由此接口所定义。

[8] 通过在Web.Config中插入特定的内容可以将自定义的HTTP模块加入到HTTP请求的处理流程中。

[9] 这是ASP.NET技术框架中的另一个核心类。

*******************************************

本系列文章结束语:

理解Http PipeLine在ASP.NET编程中有着重要的意义,只有对它有所了解,才能理解开发中遇到的种种问题,并为学习和掌握更复杂的Web开发技术(比如自定义HttpModule和HttpHandler)打下基础。

到此为止,有关ASP.NET Web编程原理的系列文章就贴完了。之所以只贴这部分,是因为我发现许多ASP.NET技术书籍对这一部分内容都语焉不详,一带而过,而这一部分又是非常重要的,期望这四篇文章能对大家有所帮助。其他的常规内容绝大多数ASP.NET技术书籍都有,就不再赘述了。

本文如有错误及疏漏之处,也恳求高手指出。

祝大家学习顺利。

ASP.NET管线与应用程序生命周期的更多相关文章

  1. asp.net应用程序生命周期和asp.net网页的生命周期

    一.asp.net应用程序生命周期 asp.net应用程序生命周期以浏览器向web服务器(比如IIS服务器)发送请求为起点,先后经历web服务器下的ISAPI(Internet Server Appl ...

  2. asp.net应用程序生命周期

    asp.net应用程序生命周期(流程文字描述版) 请求——>IIS——>ISAPI映射——>交给asp.net(即为IIS的扩展)——>通知Application类创建一个应用 ...

  3. .net学习笔记----Asp.net的生命周期之一应用程序生命周期

    Http请求刚刚到达服务器的时候 当服务器接收到一个 Http请求的时候,IIS (Internet Information Services,互联网信息服务)首先需要决定如何去处理这个请求. 什么是 ...

  4. ASP.NET 应用程序生命周期概述[转自MSDN]

    本文转自:http://msdn.microsoft.com/zh-cn/library/ms178473(VS.80).aspx 下表描述了 ASP.NET 应用程序生命周期的各个阶段.   阶段 ...

  5. IIS 7.0 的 ASP.NET 应用程序生命周期概述(转载)

    IIS 7.0 的 ASP.NET 应用程序生命周期概述更新:2007 年 11 月本主题介绍在 IIS 7.0 集成模式下运行以及与 IIS 7.0 或更高版本一起运行的 ASP.NET 应用程序的 ...

  6. ASP.NET 应用程序生命周期

    1.请求到达IIS服务器,IIS根据文件后缀找到对应的ISAPI(Internet Server API)扩展来处理,这个配置可在网站属性里的“根目录”选项卡中的“配置”里看到.可以看到,ashx.a ...

  7. Asp.net的生命周期之应用程序生命周期

    参考:http://msdn.microsoft.com/zh-cn/library/ms178473(v=vs.100).aspx 参考:http://www.cnblogs.com/JimmyZh ...

  8. IIS 5.0 和 6.0 的 ASP.NET 应用程序生命周期概述

    本主题概述 ASP.NET 应用程序的生命周期,列出了重要的生命周期事件,并描述了您编写的代码将如何适应于应用程序生命周期.本主题中的信息适用于 IIS 5.0 和 IIS 6.0.有关 IIS 7. ...

  9. [转]ASP.NET应用程序生命周期趣谈(五) IIS7瞎说

    Ps:建议初学者在阅读本文之前,先简要了解一下之前的几篇文章,以便于熟悉本文提到的一些关于IIS6的内容,方便理解.仅供参考. PS:为什么叫瞎说呢?我觉得自己理解的并不到位,只能是作为一个传声筒,希 ...

随机推荐

  1. php数据库操作类

    config.db.php <?php $db_config["hostname"] = "localhost"; //服务器地址 $db_config[ ...

  2. Android 通过广播来异步更新UI

    之前的项目里要做一个异步更新UI的功能,可是结果出现了ANR,所以想写个demo来測试究竟是哪个地方出现了问题,结果发现原来的思路是没有问题,郁闷~~ 如今这个demo 就是模拟项目里面 的步骤 1. ...

  3. Effective C++_笔记_条款00_基本术语

    (整理自Effctive C++,转载请注明.整理者:华科小涛@http://www.cnblogs.com/hust-ghtao/) 下面是每一位C++程序员都应该了解的C++词汇. 1  C++中 ...

  4. 阻塞队列BlockingQueue用法(转)

    多线程环境中,通过队列可以很容易实现数据共享,比如经典的“生产者”和“消费者”模型中,通过队列可以很便利地实现两者之间的数据共享. 假设我们有若干生产者线程,另外又有若干个消费者线程.如果生产者线程需 ...

  5. 3D-HEVC/HTM测试序列下载地址(官方完整版)

    最新3DV通用测试条件Common TestConditions of 3DV Core Experiments(JCT3V-E1100)中给出了所有标准测试序列的下载地址,有需要的朋友可以看看! 标 ...

  6. 14.5.7 Storing InnoDB Undo Logs in Separate Tablespaces 存储InnoDB Undo logs 到单独的表空间

    14.5.7 Storing InnoDB Undo Logs in Separate Tablespaces 存储InnoDB Undo logs 到单独的表空间 在MySQL 5.6.3,你可以存 ...

  7. poj 3623 Best Cow Line, Gold

    题目不算难,但是不认真想的话很容易wa,我就是wa了多次才意识到自己想法存在的缺陷. 相同的时候往后找知道出现不相同时,只能判断出当前字符的优先顺序. 这个题目如果朴素的按照这种方法做的话复杂度其实是 ...

  8. ExtJs4 笔记(2) ExtJs对js基本语法扩展支持

    本篇主要介绍一下ExtJs对JS基本语法的扩展支持,包括动态加载.类的封装等. 一.动态引用加载 ExtJs有庞大的类型库,很多类可能在当前的页面根本不会用到,我们可以引入动态加载的概念来即用即取.这 ...

  9. IT痴汉的工作现状18-思维定式

    前阵子周权出差给我带回来一个净水器,是直接安装在水龙头上的,小巧方便.我依照安装说明一步一步组装好了,感觉说明书还是比較靠谱的,没有遇到意外.但我发现它的净水.原水的button好像是有问题.它的结构 ...

  10. C#数学运算表达式解释器

    C#数学运算表达式解释器 測试文件内容: a=2+3*2; b=2*(2+3); 浏览按钮事件处理程序: private void button_browse_Click(object sender, ...