页面生命周期

来源:互联网 发布:淘宝中老年女式羊绒衫 编辑:程序博客网 时间:2024/05/21 12:39

        有很多理由去解释理解ASP.NET页面生命周期是非常重要的,主要是要去理解什么地方放置什么特定的方法,什么时候我们应该设置什么相关的属性。如果去开发自定义的服务器控件,理解生命周期对纠正控件初始化时候的错误,以及使用view-state和后台代码设置属性是非常有用的。(控件事件只与ASP.NET页面相关)

        页面生命周期要看它是否是第一次请求,还是回发(本身页面请求),最后决定是否到Web服务器。当一个网页被Web服务器请求时,在回发到web浏览器之前,会经过一系列步骤/事件(如初始化,控件实例化,state的恢复和保存,执行事件处理代码,渲染)。

        如果我们正确地使用和操作页面生命周期事件,它对web应用程序开发会是一个非常方便和强大的工具。

       IIS : 它是Microsoft .NET默认的web服务器。IIS帮助你发布web sites和web application。当IIS Web服务器接受一个Web资源(文件)的请求,它检查文件的扩展名(例如:.aspx, ascx, .ashx 和.asmx),然后决定使用哪个 ISAPI 扩展来处理这个请求,然后传递这个请求给正确的 ISAPI扩展。

       ASPNET_ISAPI.DLL: IIS加载这个dll,然后将页面请求发送给这个dll。这个dll为进一步处理而加载HTTPRuntime 。
       ASPNET_WP.EXE:它包含了应用程序池。每个应用程序池可以包含任意数量的应用程序。应用程序池也称为应用程序域。当一个网页被请求时,查找IIS的当前的应用程序正在运行的应用程序池,并且将请求转发到各自的工作进程。
       通常浏览器每次发送请求的时候,页面的生命周期每次都会执行一遍,页面的实例被创建、HTTP 运行时调用ProcessRequest 、然后执行起始页。
      下面的表格显示了每个阶段和相应的事件:
阶段 事件/方法  
页面初始化   Page_Init 
加载View State    LoadViewState  
回发数据处理 LoadPostData  
页面加载  Page_Load  
回发通知   RaisePostDataChangedEvent 
回发事件处理 RaisePostBackEvent 
页面预渲染 Page_PreRender  
保存viewstate SaveViewState  
Page渲染   Page_Render  
Page 卸载 Page_UnLoad  

 
      Asp.net确定对一个用户发起的页面请求是被解析和编译还是发送提供的网页缓存。在生命周期之前,变化非常多。在这之后,检查这个请求是否是正常的请求,在此之后,还要求检查的是一个正常的要求,回发,跨页回发或回调。
     该页面构造函数创建的控件树,在HTTP运行时实例化页面类来处理请求。
PreInit
这一事件是在页面生命周期的开始。每个页面控件初始化和根据aspx代码设置属性。
   可以改变或设置母版页或者主题
   创建或重新创建动态控件。
   读取或设置配置属性值。
Init
首先, Page的Init事件发生,然后页面上每个控件Init事件发生。在此阶段,Viewstate 信息是不可用的。
   控件已经被初始化
   如果有的话,主题皮肤被应用。
   初始化控件属性
InitComplete
    此事件是用来处理所有要求初始化都完成的任务。
PreLoad
    此事件发生在执行任何处理之前,在Load之前发生。使用这个事件,如果您在Load事件之前,需要在网页或者控件上执行相关的处理,页面实例引发此事件之前,它为页面和所有的控件加载view state 。然后处理回发数据的任何附带要求的实例。
Load :
   在控件中设置属性, 建立数据库的连接
Control Events :
   有一些控件的特定的事件,例如: Button Click, DropDownIndexChanged 等等。
Load Complete
   这些事件用来处理一些在Load事件处理完成之后需要处理的任务。
PreRender
   在这种事件中,页面可以确保所有子控件都被创建。页面为所有的子控件调用EnsureChildControls也包括自己。每一个控件的数据源/绑定属性设置为它的绑定方法调用。
SaveStateComplete
   这个事件发生在页面和所有的控件的编码和保存viewstate之后。
Render
   每一个asp.net控件都有渲染方法,页面的实例调用此方法并输出控件的标记
Unload
   Unload事件用来执行清除任务,像关闭数据库连接,关闭打开的文件,完成日志,以及一些其他的任务。该事件首先针对每个控件发生,继而针对该页发生。

 

 

 

 

当一个客户端页面访问IIS试图获取一些信息的时候,发生了什么事情?一个请求在通过了HTTP管道后又发生了什么?本文主要是描述这两个过程,即IIS处理asp.net请求和asp.net的页面生命周期。欢迎大家积极拍砖,共同学习,共同进步。

  首先我们要弄清楚两个非常重要的概念:

  1, worker process(w3wp.exe). worker process管理所有的来自客户端的请求并给出响应。它是IIS下asp.net应用程序的核心。

  2, application pool. 它是worker process的容器,IIS5及之前的IIS版本均没有application pool的概念。每一个application pool对应着一个worker process,在IIS Metabase中维护着Application Pool和worker process的Mapping。这就避免了IIS5中出现的worker process(IIS5中是aspnet_wp.exe,同一时间只能运行一个该进程)崩溃,application全崩溃的局面。

  客户端向IIS发出一个资源请求后发生了如下事情:

  1, server接受该请求

  IIS6通过内核模式(Kernel mode)中的HTTP.SYS来分发各个Request到application pool。 这并不是随机的过程,在application pool创建的时候就已经注册到了HTTP.SYS,所以当请求来到时HTTP.SYS会直接发送到相应的application pool。 接下来在IIS的用户模式(User mode)中,Web Admin Services (WAS) 做了从HTTP.SYS中得到Request并分发到application pool的工作。application pool直接把request传递给worker process。

  2, 请求传递到worker process后,worker process初始化加载ASP.NET ISAPI(Internet Server Application Program Interface),ASP.NET ISAPI进而加载CLR创建托管环境。

  (注:ISAPI只是一个接口,起到一个代理的作用,主要能力就是根据Request URL的后缀来寻找该后缀的处理程序)

  ASP.NET ISAPI定义在aspnet_isapi.dll中,它本身运行在一个非托管的环境中。ASP.NET ISAPI开始一个HttpRuntime, HttpRuntime调用ProcessRequest方法来开始处理请求。ProcessRequest根据ISAPI传进来的iWRType 来创建不同的HttpWorkerRequest,从而屏蔽了不同IIS的差异。接下来ProcessRequest方法创建了HttpContext,我们使用HTTPContext.Current来访问它。在HttpRuntime使用HttpApplicationFactory创建了HttpApplication对象(IHttpHandler)以后,所有的请求都会在通过httpmodule后找到相应的Httphandler进行处理。在HttpApplicationFactory创建HttpApplication之前,会查找config(web.config和Machine.config)文件中注册的所有的HttpModule,并根据配置信息加载相应的Assembly,通过Reflection创建对应的HttpModule,并将这些Module加到HttpApplication 的_moduleCollection Filed中。我们对一个Application的请求最终会落到一个HttpApplication对象上。当一个请求到来时,ASP.NET会在Httplication Pool中查找未被使用的HttpApplication对象。

  3, 请求通过HTTP管道后,每个请求都发向相关的各自的httphandler,IIS请求处理过程结束。

  HttpHandler是HTTP管道的终点,它为每个request生成输出。System.Web.UI.Page就是这样一个典型的Httphandler,当我们请求一个aspx页面,这个HttpHandler就生成html发送回客户端。看Page类的签名:

  public class Page : TemplateControl, IHttpHandler

  {

  }

  可以看到,Page类就是一个HttpHandler。

  综上整个过程就是:当客户端向服务器发送资源请求时,请求首先到达IIS的HTTP.SYS。然后HTTP.SYS发送请求道对应的Application Pool。 然后Application Pool发送请求到Worker Process(W3WP.exe)中加载ISAPI Extension,ISAPI创建一个HttpRuntime对象来通过HttpModule和HttpHandler处理请求。 然后页面生命周期就开始了。

  4, 页面生命周期开始

  页面生命周期的主要阶段包括:

  页面初始化(Init): 服务器创建服务器控件的实例

  加载(load): 控件实例被加载到它定义的页面对象中

  预输出:(PreRender) 对控件的更改被更新,准备输出。

  保存(SaveViewState): 控件的状态信息被保存。

  输出页面(Render):服务器为控件创建html标记。

  处理(Dispose): 主要做的工作就是dispose, 关闭数据库连接,文件资源的释放等。

  卸载(Unload):销毁服务器控件的实例

  页面生命周期的主要事件:

  PreInit:

  1.检查IsPostBack 属性

  2.动态设置Master Page

  3.动态设置Theme

  4.设置控件的默认值(UniqueId等)

  5.重新创建动态控件(初始化控件),初始化控件的值

  Init: 这个事件发生在所有的控件被初始化,所有的皮肤设置被应用以后。它用来读取或者初始化控件属性。它能够用来注册一些aspx页面中没有指出的控件的事件。

  InitComplete: Use this event for processing tasks that require all initialization to be complete.

  PreLoad: 加载页面的ViewState和所有的控件,然后处理所有的包含在Request实例中的postback数据。

  Load: 这个事件可能是大家最熟悉的了。需要注意的是,Page对象会递归的调用子控件的onload事件直到页面和所有的子控件被加载完成。这个事件主要用来设置控件属性的值,建立数据库连接(通常不这么做)。

  Control events: 这个就不多说了,主要是处理控件的事件,例如click。这也就让我们明白了每次我们click一个Button的时候,实际上是要先去执行load事件然后才执行click事件的,一般我们用!IsPostBack来判断一下从而避免执行不必要的加载逻辑。

  LoadComplete: 页面所有的控件都被加载以后执行,暂时没有想到用来干什么。。。

  PreRender: 在HTML被生成之前这是最后一个事件。每一个页面中的控件都有PreRender的过程。在这里对将要输出的HTML结果进行最后一次修改。

  SaveStateComplete: 在这个时间发生之前,已经保存了所有控件和页面的,任何对page或者控件的改动都不会产生左右。暂时没想到用来干啥。

  Render: 它不是一个事件而是一个方法。工作就是把HTML写回客户端浏览器。

  UnLoad: 页面中的每一个控件都会发生这件事。在控件中,使用这个事件来做清理工作,例如关闭数据库连接等。对与页面本身也是做清理工作,例如关闭打开的文件和数据库连接,或者结束日志或者其它指定的工作。

  需要说明的是,每次Request都会创建一个全新的Page类的实例,所以在页面中的自己定义的字段是不能在两次request中传递值的,需要使用viewstate来存储。

  5, HttpHandler根据页面生命周期中事件的处理把结果发回IIS,IIS再把结果发回客户端浏览器。

  值得注意的是,在这个过程中请求会再次通过HttpModule(注册一个EndRequest事件)。

  至此,整个Request结束。