天天看点

记不住ASP.NET页面生命周期的苦恼

对于ASP.NET开发者,理解ASP.NET的页面生命周期是非常重要的。主要是为了搞明白在哪里放置特定的方法和在何时设置各种页面属性。但是记忆和理解页面生命周期里提供的事件处理方法(method)非常困难。互联网上有很多关于页面生命周期内部机制的文章,所以本文只准备简单覆盖技术的基础部分,更主要的目的是给大家提供一个简单得记忆页面生命周期的方法。

准确的记忆ASP.NET页面生命周期每一个阶段发生了什么事情是比较困难的,一种便于记忆的方法是根据各个阶段的名字组合出一个缩写。微软的文档给出的ASP.NET生命周期如下:

Page Request

Start

Page Initialization

Load

Validation

Postback event handling

Rendering

Unload

根据这个组合出一个缩写非常容易。既然Page Request技术上并不是页面生命周期的一部分(这个阶段仅仅标示我们是否开始一个页面周期或者从缓存加载一个页面),我们为了方便,就不包括这一阶段。

S – Start

I – Initialize

L – Load

V – Validate

E – Event Handling

R – Render

这样就组合出一个缩写“SILVER',这个英文单词非常好记。当然,一定要记住页面生命周期的最后一个环节unload没有包括在里面。如果你觉得有必要,你可以记忆为“SILVER-U”或者“SILVER-YOU",尽管有点破坏这个记忆法的完美性。现在,我们非常容易就记住了页面生命周期,接着我们总结一下每一步都发生了什么,都有什么事件伴随着发生。

在这个阶段,页面属性,比如<code>Request</code>, <code>Response</code>, <code>IsPostBack</code>和<code>UICulture被创建。最为一个开发人员,大部分时候在这个阶段你不需要做任何事。 如果你需要调用或者重写(override)这一阶段的行为,可以使用PreInit方法创建或者重新创建动态控件,设置master page或者theme或者读取和设置profile property的值。要注意的一点是,如果是回传(postback)的页面请求,所有控件的值还没有从view state里还原,如果你在这个阶段设置一个控件的值,这个值有可能在下面的阶段被重写并覆盖。</code>

这个阶段对于开发人员是很重要。在这个阶段,theme被应用,所有的控件都被设置了唯一的ID。开发人员在这个阶段可以调用<code>Init</code>, <code>InitComplete</code>和<code>PreLoad</code> 方法。微软关于这些方法使用的建议如下:

<code>Init</code>– 这个事件发生在所有控件被初始化并且皮肤设置也被应用后。使用这个事件来读取控件的初始化值。

<code>InitComplete</code>–这个事件被Page对象触发,使用这个事件处理那些要求所有初始化工作都完成后才能做的事情。

<code>PreLoad</code>- 如果在页面或者控件进入Load事件前你有什么要处理的,使用这个事件。Page在触发这个事件后,Page就会为自己和所有的控件加载view state并且处理所有Request中的postback数据。

这个阶段可能是开发者使用得最多的一个阶段。在这个阶段,所有的控件被viewstate中信息填充并被加载,OnLoad事件被触发。在这个阶段你可以为页面上所有的服务端控件设置属性,得到query strings,建立数据库连接。

如果你的控件要求验证,验证会在这个阶段发生,这个时候你可以检查控件的IsValid属性。跟这个阶段关联的事件是Validate,它有一个可以接受验证字符串群的重载方法(overload method),这个重载方法执行特定控件群的验证。

所有服务器端控件的事件处理发生在这个阶段。也就是说<code>Click</code>, <code>SelectedIndexChanged</code>等等这些事件会应用到你的服务器端控件,如果是页面请求是回传(postback)的话,这些事件的处理函数就会被控件触发。这个阶段可以使用的事件如下:

<code>LoadComplete</code>– 在这个阶段,页面上所有的控件加载完毕。

<code>PreRender</code>– 这里有几个重点,第一:页面对象(page object)会调用每一个控件的EnsureChildControls函数,并最终调用自己的。其次:所有具有DataSourceID的数据绑定控件都会调用自己的DataBind函数。要注意的一点是,PreRender事件会发生在一个页面的每一个控件上。在这个事件的最后,页面和所有控件的ViewState被存储。

<code>SaveStateComplete</code>– 到这里,ViewState已经存储完毕,如果你有什么操作不需要修改控件但需要修改ViewState的,可以放在SaveStateComplete里面。

最后这个事件首先是被各个控件逐一触发,最后被页面触发。在这个时刻,所有的控件已经被渲染为输出流(output stream)并且无法被修改。这个阶段中,任何试图对response stream的操作都会引发异常。这个事件主要用于做一些清理工作,比如关闭数据库连接和打开的文件或者登记事件记录等等其它任务。

下面列出ASP.NET页面生命周期中所有的方法,这些方法都可以被重写(override),要注意的是这些方法有的会递归调用,有个会被页面中的内容重复调用,这个列表是按照页面加载时最通用的顺序排列的。

<code>Construct</code>

<code>ProcessRequest</code>

<code>FrameworkInitialize</code>

<code>InitializeCulture</code>

If child controls are present:

<code>AddParsedSubObject</code>

<code>CreateControlCollection</code>

<code>AddedControl</code>

<code>ResolveAdapter</code>

<code>DeterminePostBackMode</code>

<code>OnPreInit</code>

<code>OnInit</code>

<code>TrackViewState</code>

<code>OnInitComplete</code>

<code>OnPreLoad</code>

<code>OnLoad</code>

<code>OnLoadComplete</code>

<code>EnsureChildControls</code>

<code>CreateChildControls</code>

<code>OnPreRender</code>

<code>OnPreRenderComplete</code>

<code>SaveViewState</code>

<code>OnSaveStateComplete</code>

<code>CreateHtmlTextWriter</code>

<code>RenderControl</code>

<code>Render</code>

<code>RenderChildren</code>

<code>VerifyRenderingInServerForm</code>

<code>OnUnload</code>

<code>Dispose</code>

在开发ASP.NET程序时,了解什么时候发生什么事情是非常重要的。理解页面中事件是如何层层展开节省大量挠头和查错的时间。当这些页面周期中的事件难以记住时,我希望这个使用的法子能帮助你梳理出在程序里哪个地方需要做什么处理。

我写这篇文章是为了帮助大家,也方便了自己。即使是熟练的开发人员有时也会忘记那些先那些后。这篇文章不是面面俱到,而是希望给初学者和中级水平的开发者提供一些“小技巧”,从而帮助他们避免一些基本的错误。

祝使用ASP.NET一路愉快!

本文译者:m2land

本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。