【译】ASP.NET应用程序和页面生命周期

为什么翻译此文

  1、此文是Code Project社区2010年4月ASP.NET板块的最佳文章,说明了此文的分量;html

  2、锻炼本身的英文技术文章翻译能力,提升英文技术文档阅读能力;数据库

  3、了解掌握ASP.NET页面生命周期是很是必要的,这有助于咱们更加灵活的控制页面,以咱们须要的方式编程开发;编程

关于原文做者

原文做者:Shivprasad koirala
原文地址:http://www.codeproject.com/Articles/73728/ASP-NET-Application-and-Page-Life-Cycle
他的介绍:微软MVP(ASP/ASP.NET),如今是印度一家小型在线教育公司的CEO。他很是积极地在制做在线培训视频,写技术书籍及作企业培训。

内容导读

  • 概述
  • 大致上的两步处理流程
  • ASP.NET环境的建立
  • 经过MHPM触发的事件处理请求
  • 在什么事件中咱们能够作什么?
  • 一个简单的示例
  • 详解ASP.NET页面事件

1、概述

  在本文中,咱们会试着了解用户在浏览器中发出一个Web请求 到 这个请求被响应并显示在浏览器中的过程当中究竟会发生哪些不一样的事件。首先,咱们先试着了解一下ASP.NET请求的两个大致上的步凑,而后咱们将关注点转移到从'HttpHandler'、'HttpModule'以及ASP.NET页面对象所触发的不一样事件上。当咱们进入这个事件之旅时,咱们也会试着明白在请求处理的每一个事件当中咱们能够作什么业务逻辑处理操做。api

2、大致上的两步处理流程

  大致上,ASP.NET请求的处理流程分为以下图所示的两个步凑。用户发送一个请求到IIS服务器时:浏览器

  (1)ASP.NET会建立一个可以处理请求的环境。换句话说,它会建立一个包含请求、响应以及上下文对象的应用程序对象来处理这个请求。缓存

  (2)一旦ASP.NET环境被建立,用户请求就会经过由modules(管道)、handlers(处理程序)和page objects(页面对象)触发的一系列事件进行处理。简而言之,咱们暂且将此步凑称为MHPM(Module、Handler、Page和Module Event)。服务器

Two Main Steps

 

  图1 ASP.NET的两个主要处理步凑框架

  在接下来的部分中,咱们会深刻地理解这两个主要的步凑。ide

3、ASP.NET环境的建立

  第一步:用户请求到达IIS后,IIS首先会检查哪个ISAPI扩展可以处理这个请求,这会取决于文件的后缀名。例如:若是请求的是一个'.aspx'的页面,那么就会被传递到'aspnet_isapi.dll'来进行处理。post

  第二步:若是这是该网站的首次请求,那么一个称为'ApplicationManager'的类会首先建立一个该网站能够运行的应用程序域(App Domain)。正如咱们所知,应用程序域隔离部署在同一台IIS服务器上的两个不一样的Web应用程序。所以,即便其中一个应用程序域出现了错误,也不会影响其余应用程序域的正常运做。

Note:下面的内容是我补充的,非原文内容。

.NET平台下,程序集并无直接加载进 进程 中(传统的Win32程序是直接承载的)。.NET可执行程序承载在进程的一个逻辑分区中,术语称应用程序域(简称AppDomain)。应用程序域是.NET引入的一个新概念,它比进程所占用的资源要少,能够被看做是一个 轻量级的进程

在一个进程中能够包含多个应用程序域,一个应用程序域能够装载一个可执行程序(*.exe)或者多个程序集(*.dll)。这样可使应用程序域之间实现深度隔离,因此:即便进程中的某个应用程序域出现错误,也不会影响其余应用程序域的正常运做。

更多关于AppDomain的介绍,请自行搜索,这里再也不赘述。

  第三步:在新建立的应用程序域中,会建立ASP.NET的宿主环境,也就是HttpRuntime对象。一旦宿主环境被建立完成,ASP.NET最核心的对象如HttpContextHttpRequestHttpResponse对象都会被建立好。

  第四步:一旦全部核心的ASP.NET对象被建立好,HttpApplication对象就会随之被建立来服务这个请求。若是你的系统中存在一个global.asax文件,那么这个global.asax文件的对象也会被建立。可是,须要注意的是你的global.asax须要继承自HttpApplication类。

  注意:在一个ASP.NET页面第一次附加到网站,一个HttpApplication实例便随之产生。为了最大化得提升处理性能,HttpApplication的实例将会被复用以处理多个请求。

Note:下面的内容是我补充的,非原文内容。

Global.asax 文件(也称做 ASP.NET 应用程序文件)是可选文件,包含用于响应 ASP.NET 或 HttpModule 引起的应用程序级别事件的代码。(换句话说,咱们能够自定义后面咱们所要介绍的一些事件,由于请求处理流程会经历后面的10多个事件,咱们能够写代码来自定义其中的一些事件,加一些咱们想作的业务逻辑操做,好比:URL重写、身份验证、图片水印等等。)

若是不定义该文件,ASP.NET 页框架假设您未定义任何应用程序或会话事件处理程序。

  第五步:此时HttpApplication对象将会被分配给一系列的ASP.NET核心对象来处理请求的页面。

  第六步:这时,HttpApplication开始经过HTTP管道事件、处理程序(Handlers)和页面事件来处理请求了。也就是说:它会触发 MHPM 中的事件来处理请求。

  么么嗒,你也能够经过下图来详细地了解这几个步凑。

Create Environment Steps

  图2 ASP.NET环境的建立

  下图则形象地展现了在一个ASP.NET请求过程当中的重要内部对象模型。最高层是ASP.NET运行时,它建立了一个应用程序域(AppDoamin),下层则建立了一个包含request、response以及context对象的HttpRuntime。

General Explain Steps

 图3 ASP.NET请求过程当中的内部对象模型

4、经过MHPM触发的事件处理请求

  一旦HttpApplication建立好,它就开始处理请求了。它经历了三个不一样的部分:HttpModulePageHttpHandler。当它通过这些部分时,它将调用不一样的事件,而这些事件的逻辑处理还能够由开发者来进行扩展和增长自定义处理。

  在进一步深刻了解以前,让咱们先来了解一下什么是HttpModuleHttpHandlers。他们帮助咱们在ASP.NET页面处理过程的先后注入自定义的逻辑处理。他们之间主要的差异在于:

  • 若是你想要注入的逻辑是基于像'.aspx','.html'这样的扩展名,那么你可使用HttpHandler。换句话说,HttpHandler是一个基于处理器的扩展。

HttpHandler Show

图4 HttpHandler

  • 若是你想要在ASP.NET管道事件中注入逻辑,那么你可使用HttpModule。也能够说,HttpModule是一个基于处理器的事件。

HttpModule Show

图5 HttpModule

  你能够从这里了解更多关于他们这对好基友之间的差异。

  下面是请求处理过程的逻辑流程,其中有4个重要的步凑,解释以下:

  第一步(M:HttpModule):客户端请求开始被处理。在ASP.NET引擎执行和建立HttpModule触发事件(在此过程当中,你也能够注入自定义逻辑)以前,有6个事件你能够在页面对象建立以前来使用,它们分别是:BeginRequestAuthenticateRequestAuthorizeRequestResolveRequestCacheAcquireRequestState 以及 PreRequestHandlerExecute

  第二步(H:HttpHandler):一旦以上6个事件被触发后,ASP.NET引擎就将会调用 ProcessRequest 事件,即便你已经在项目中实现了 HttpHandler

  第三步(P:ASP.NET Page):一旦HttpHandler逻辑执行,ASP.NET页面对象就被建立了。而ASP.NET页面被建立,一系列的事件也会随之被触发,它们能够帮助咱们自定义逻辑注入到这些事件里边。在此过程当中,有6个重要事件给咱们提供了占位符,以便咱们在ASP.NET页面中写入逻辑,它们分别是:InitLoadValidateRender Unload。你能够经过记住单词SILVER来记忆这几个事件,S—Start(没有任何意义,仅仅是为了造成一个单词),I(Init)、L(Load)、V(Validate)、E(Event)、R(Render)。

  第四步(M:HttpModule):一旦页面对象执行结束并从内存中被卸载,HttpModule提供了提交返回页面的执行事件,一样,在这些事件中也能够被注入自定义的返回处理逻辑。这里有4个重要的提交处理事件:PostRequestHandlerExecuteReleaserequestStateUpdateRequestCache以及EndRequest

  下图形象地展现了上面的四个步凑。

MHPM

图6 MHPM过程

5、在什么事件中咱们能够作什么?

  一个十分有价值的问题就是在什么事件中咱们又能够作些什么?下表就展现了这个问题的答案:

Section Event Description
HttpModule BeginRequest 此事件标志着一个新的请求,它保证在每一个请求中都会被触发。
HttpModule AuthenticateRequest 此事件标志ASP.NET运行时准备验证用户。任何身份验证代码均可以在此注入。
HttpModule AuthorizeRequest 此事件标志ASP.NET运行时准备受权用户。任何受权代码均可以在此注入。
HttpModule ResolveRequest 在ASP.NET中咱们一般使用OutputCache指令作缓存。在这个事件中,ASP.NET运行时肯定是否可以从缓存中加载页面,而不是从头开始生成。任何缓存的具体活动能够被注入这里。
HttpModule AcquireRequestState 此事件标志着ASP.NET运行时准备得到Session会话变量。能够对Session变量作任何你想要作的处理。
HttpModule PreRequestHandlerExecute 刚好在ASP.NET 开始执行事件处理程序前发生。能够预处理你想作的事。
HttpHandler ProcessRequest HttpHandler逻辑被执行。在这个部分咱们将为每一个页面扩展写须要的逻辑。
Page Init 此事件发生在ASP.NET页面且能够用来: 
一、动态地建立控件,若是你必定要在运行时建立控件; 
二、任何初始化设置 
三、母版页及其设置 
在这部分中咱们没有得到viewstate、postedvalues及已经初始化的控件。
Page Load 在这部分ASP.NET控件彻底被加载且在这里你能够写UI操做逻辑或任何其余逻辑。NOTE:这个事件也是咱们最多见且最经常使用的一个事件。
Page Validate 若是在页面上你有验证器,你一样想在这里作一下检查。
Page Render 是时候将输出发送到浏览器。若是你想对最终的HTML作些修改,你能够在这里输入你的HTML逻辑。
Page Unload 页面对象从内存中卸载。
HttpModule PostRequestHandlerExecute 能够注入任何你想要的逻辑,在处理程序执行以后。
HttpModule ReleaseRequestState 若是你想要保存对某些状态变量的更改,例如:Session变量的值。
HttpModule UpdateRequestCache 在结束以前,你是否想要更新你的缓存。
HttpModule EndRequest 这是将输出发送到客户端浏览器以前的最后一个阶段。

6、一个简单的示例

  咱们能够经过一个示例程序代码来展现以上介绍的那些事件是怎样被最终触发的。在这个示例中,咱们已经建立了一个HttpModuleHttpHandler,而且也在全部的事件中经过添加自定义逻辑代码展现了一个简单的响应。

  下面是HttpModule类,它跟踪了全部的事件并将其添加到了一个全局的集合中。

public class clsHttpModule : IHttpModule
{
...... 
void OnUpdateRequestCache(object sender, EventArgs a)
{
objArrayList.Add("httpModule:OnUpdateRequestCache");
}
void OnReleaseRequestState(object sender, EventArgs a)
{
objArrayList.Add("httpModule:OnReleaseRequestState");
}
void OnPostRequestHandlerExecute(object sender, EventArgs a)
{
objArrayList.Add("httpModule:OnPostRequestHandlerExecute");
}
void OnPreRequestHandlerExecute(object sender, EventArgs a)
{
objArrayList.Add("httpModule:OnPreRequestHandlerExecute");
}
void OnAcquireRequestState(object sender, EventArgs a)
{
objArrayList.Add("httpModule:OnAcquireRequestState");
}
void OnResolveRequestCache(object sender, EventArgs a)
{
objArrayList.Add("httpModule:OnResolveRequestCache");
}
void OnAuthorization(object sender, EventArgs a)
{
objArrayList.Add("httpModule:OnAuthorization");
}
void OnAuthentication(object sender, EventArgs a)
{

objArrayList.Add("httpModule:AuthenticateRequest");
}
void OnBeginrequest(object sender, EventArgs a)
{

objArrayList.Add("httpModule:BeginRequest");
}
void OnEndRequest(object sender, EventArgs a)
{
objArrayList.Add("httpModule:EndRequest");
objArrayList.Add("<hr>");
foreach (string str in objArrayList)
{
httpApp.Context.Response.Write(str + "<br>") ;
}
} 
}
View Code

  下面是HttpHandler类的一个代码片断,它跟踪了ProcessRequest事件。

public class clsHttpHandler : IHttpHandler
{
public void ProcessRequest(HttpContext context)
{
clsHttpModule.objArrayList.Add("HttpHandler:ProcessRequest");
context.Response.Redirect("Default.aspx");
}
}
View Code

  同上,咱们也能够跟踪来自ASP.NET Page页面的全部事件。

public partial class _Default : System.Web.UI.Page 
{
protected void Page_init(object sender, EventArgs e)
{

clsHttpModule.objArrayList.Add("Page:Init");
}
protected void Page_Load(object sender, EventArgs e)
{
clsHttpModule.objArrayList.Add("Page:Load");
}
public override void Validate() 
{
clsHttpModule.objArrayList.Add("Page:Validate");
}
protected void Button1_Click(object sender, EventArgs e)
{
clsHttpModule.objArrayList.Add("Page:Event");
}
protected override void Render(HtmlTextWriter output) 
{
clsHttpModule.objArrayList.Add("Page:Render");
base.Render(output);
}
protected void Page_Unload(object sender, EventArgs e)
{
clsHttpModule.objArrayList.Add("Page:UnLoad");
}
}
View Code

  下图则显示了上面咱们所讨论的全部事件的执行顺序。

A Sample Demo

图7 示例结果—事件的执行次序

7、详解ASP.NET页面事件

  在上面的部分中,咱们已经了解了一个ASP.NET页面请求事件的总体流程。那么,在其中一个最重要的部分就是ASP.NET页面,可是咱们并无对其进行详细讨论。所以,咱们在此深刻地了解一下ASP.NET页面事件。

  每个ASP.NET页都有2个部分:一个是在浏览器中进行显示的部分,它包含了HTML标签、viewstate形式的隐藏域 以及 在HTML input中的数据。当这个页面被提交到服务器时,这些HTML标签会被建立到ASP.NET控件,而且viewstate还会和表单数据绑定在一块儿。一旦你在后置代码中获得全部的服务器控件,你能够执行和写入你本身的逻辑并呈现给客户浏览器。

ASP.NET Page

图8 ASP.NET页的两个部分

  如今这些HTML控件会做为ASP.NET控件存活在服务器上,ASP.NET会触发一系列的事件,咱们也能够在这些事件中注入自定义逻辑代码。根据你想要执行什么样的任务/逻辑,咱们须要将逻辑合理地放入这些事件之中。

  注意:大部分的开发者直接使用Page_Load来干全部的事情,但这并非一个好的思路。所以,不管是填充控件、设置ViewState仍是应用主题等全部发生在页面加载中的全部事情。所以,若是咱们可以在合适的事件中放入逻辑,那么毫无疑问咱们代码将会干净不少。  

顺序 事件名称 控件初始化 ViewState可用 表单数据可用 什么逻辑能够写在这里?
1 Init No No No 注意:你能够经过使用ASP.NET请求对象访问表单数据等,但不是经过服务器控件。
动态地建立控件,若是你必定要在运行时建立;任何初始化设置;母版页及其设置。在这部分中咱们没有得到viewstate、提交的数据值及已经初始化的控件。
2 Load View State Not guaranteed Yes Not guaranteed 你能够访问View State及任何同步逻辑,你但愿viewstate被推到后台代码变量能够在这里完成。
3 PostBackdata Not guaranteed Yes Yes 你能够访问表单数据。任何逻辑,你但愿表单数据被推到后台代码变量能够在这里完成。
4 Load Yes Yes Yes 在这里你能够放入任何你想操做控件的逻辑,如从数据库填充combox、对grid中的数据排序等。这个事件,咱们能够访问全部控件、viewstate、他们发送过来的值。
5 Validate Yes Yes Yes 若是你的页面有验证器或者你想为你的页面执行验证,那就在这里作吧。
6 Event Yes Yes Yes

若是这是经过点击按钮或下拉列表的改变的一个回发,相关的事件将被触发。与事件相关的任何逻辑均可以在这里执行。

PS:这个事件想必不少使用WebForm的开发人员都很经常使用吧,是否记得那些Button1_Click(Object sender,EventArgs e)?

7 Pre-render Yes Yes Yes 若是你想对UI对象作最终的修改,如改变属性结构或属性值,在这些控件保存到ViewState以前。
8 Save ViewState Yes Yes Yes 一旦对服务器控件的全部修改完成,将会保存控件数据到View State中。
9 Render Yes Yes Yes 若是你想添加一些自定义HTML到输出,能够在这里完成。
10 Unload Yes Yes Yes 任何你想作的清理工做均可以在这里执行。

Page Events in Detail

图9 ASP.NET Page事件流程

一张图复习ASP.NET请求处理(本身补充,非原文内容)

翻译中参考的资料 

(1)碧血轩,《ASP.NET页面生命周期》,http://www.cnblogs.com/xhwy/archive/2012/05/20/2510178.html

(2)吴秦,《ASP.NET 应用程序与页面生命周期(意译)》,http://www.cnblogs.com/skynet/archive/2010/04/29/1724020.html

(3)风尘浪子,《C#综合揭秘—细说进程、应用程序域与上下文之间的关系》,http://www.cnblogs.com/skynet/archive/2010/04/29/1724020.html

(4)菩提树下的杨过,《温故而知新:HttpApplication,HttpModule,HttpContext及Asp.Net页生命周期》,http://www.cnblogs.com/yjmyzz/archive/2010/03/28/1698968.html

(5)MSDN,《ASP.NET页面生命周期概述》,http://msdn.microsoft.com/zh-cn/library/ms178472.aspx

(6)皱华栋,《ASP.NET!=拖控件之2011版视频教程》,http://bbs.itcast.cn/thread-8439-1-1.html

 

相关文章
相关标签/搜索