首页 > 编程 > .NET > 正文

IIS处理Asp.net请求和Asp.net页面生命周期详细说明

2020-01-18 00:34:07
字体:
来源:转载
供稿:网友
ASP.NET 页运行时,此页将经历一个生命周期,在生命周期中将执行一系列处理步骤。这些步骤包括初始化、实例化控件、还原和维护状态、运行事件处理程序代码以及进行呈现。了解页生命周期非常重要,因为这样做您就能在生命周期的合适阶段编写代码,以达到预期效果。此外,如果您要开发自定义控件,就必须熟悉页生命周期,以便正确进行控件初始化,使用视图状态数据填充控件属性以及运行任何控件行为代码。(控件的生命周期基于页的生命周期,但是页引发的控件事件比单独的 ASP.NET 页中可用的事件多。)

      一般来说,页要经历下表概述的各个阶段。除了页生命周期阶段以外,在请求前后还存在应用程序阶段,但是这些阶段并不特定于页。(有关更多信息,请参见 MSDN:ASP.NET 应用程序生命周期概述。)

      我们知道最终我们在服务器上创建的页面对象是通过Page的一个派生类来创建的,这个类通常情况下是看不到的,包括类的名字也不是我们直接指定的。这个类是由ASP.NET服务器根据我们的页面模板文件aspx创建出来的,页面对象的ProcessRequest方法将会启动页面的生成过程。这个过程是通过页面的处理管道来完成的。

      下表列出了最常用的页生命周期事件。除了列出的事件外还有其他事件;不过,大多数页处理方案不使用这些事件。而是主要由 ASP.NET 网页上的服务器控件使用,以初始化和呈现它们本身。如果要编写自己的 ASP.NET 服务器控件,则需要详细了解这些阶段。(有关创建自定义控件的信息,请参见MDDN:开发自定义 ASP.NET 服务器控件。 )

      注意事项(来自MSDN):

      各个 ASP.NET 服务器控件都有自己的生命周期,该生命周期与页生命周期类似。例如,控件的 InitLoad 事件在相应的页事件期间发生。

      虽然 InitLoad 都在每个控件上以递归方式发生,但它们的发生顺序相反。每个子控件的 Init 事件(还有 Unload 事件)在为其容器引发相应的事件之前发生(由下到上)。但是,容器的 Load 事件是在其子控件的 Load 事件之前发生(由上到下)。

可以通过处理控件的事件(如 Button 控件的 Click 事件和 ListBox 控件的 SelectedIndexChanged 事件)来自定义控件的外观或内容。在某些情况下,可能也需处理控件的 DataBindingDataBound 事件。有关更多信息,请参见各个控件的类参考主题以及开发自定义 ASP.NET 服务器控件

      当从 Page 类继承类时,除了可以处理由页引发的事件以外,还可以重写页的基类中的方法。例如,可以重写页的 InitializeCulture 方法,以便动态设置区域性信息。注意,在使用 Page_事件语法创建事件处理程序时,将隐式调用基实现,因此无需在方法中调用它。例如,无论是否创建 Page_Load 方法,始终都会调用页基类的 OnLoad 方法。但是,如果使用 override 关键字(在 Visual Basic 中为 Overrides)重写页的 OnLoad 方法,则必须显式调用基方法。例如,如果在页中重写 OnLoad 方法,则必须调用 base.Load(在 Visual Basic 中为 MyBase.Load)以运行基实现。

IIS处理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结束。

发表评论 共有条评论
用户名: 密码:
验证码: 匿名发表