html
数据库
编程
![]() |
原文做者:Shivprasad koirala |
原文地址:http://www.codeproject.com/Articles/73728/ASP-NET-Application-and-Page-Life-Cycle |
|
他的介绍:微软MVP(ASP/ASP.NET),如今是印度一家小型在线教育公司的CEO。他很是积极地在制做在线培训视频,写技术书籍及作企业培训。 |
api
浏览器
缓存
服务器
框架
ide
post
图2 ASP.NET环境的建立
下图则形象地展现了在一个ASP.NET请求过程当中的重要内部对象模型。最高层是ASP.NET运行时,它建立了一个应用程序域(AppDoamin),下层则建立了一个包含request、response以及context对象的HttpRuntime。
图3 ASP.NET请求过程当中的内部对象模型
一旦HttpApplication建立好,它就开始处理请求了。它经历了三个不一样的部分:HttpModule、Page和HttpHandler。当它通过这些部分时,它将调用不一样的事件,而这些事件的逻辑处理还能够由开发者来进行扩展和增长自定义处理。
在进一步深刻了解以前,让咱们先来了解一下什么是HttpModule和HttpHandlers。他们帮助咱们在ASP.NET页面处理过程的先后注入自定义的逻辑处理。他们之间主要的差异在于:
图4 HttpHandler
图5 HttpModule
你能够从这里了解更多关于他们这对好基友之间的差异。
下面是请求处理过程的逻辑流程,其中有4个重要的步凑,解释以下:
第一步(M:HttpModule):客户端请求开始被处理。在ASP.NET引擎执行和建立HttpModule触发事件(在此过程当中,你也能够注入自定义逻辑)以前,有6个事件你能够在页面对象建立以前来使用,它们分别是:BeginRequest、AuthenticateRequest、AuthorizeRequest、ResolveRequestCache、AcquireRequestState 以及 PreRequestHandlerExecute。
第二步(H:HttpHandler):一旦以上6个事件被触发后,ASP.NET引擎就将会调用 ProcessRequest 事件,即便你已经在项目中实现了 HttpHandler。
第三步(P:ASP.NET Page):一旦HttpHandler逻辑执行,ASP.NET页面对象就被建立了。而ASP.NET页面被建立,一系列的事件也会随之被触发,它们能够帮助咱们自定义逻辑注入到这些事件里边。在此过程当中,有6个重要事件给咱们提供了占位符,以便咱们在ASP.NET页面中写入逻辑,它们分别是:Init、Load、Validate、Render 和 Unload。你能够经过记住单词SILVER来记忆这几个事件,S—Start(没有任何意义,仅仅是为了造成一个单词),I(Init)、L(Load)、V(Validate)、E(Event)、R(Render)。
第四步(M:HttpModule):一旦页面对象执行结束并从内存中被卸载,HttpModule提供了提交返回页面的执行事件,一样,在这些事件中也能够被注入自定义的返回处理逻辑。这里有4个重要的提交处理事件:PostRequestHandlerExecute、ReleaserequestState、UpdateRequestCache以及EndRequest。
下图形象地展现了上面的四个步凑。
图6 MHPM过程
一个十分有价值的问题就是在什么事件中咱们又能够作些什么?下表就展现了这个问题的答案:
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 | 这是将输出发送到客户端浏览器以前的最后一个阶段。 |
咱们能够经过一个示例程序代码来展现以上介绍的那些事件是怎样被最终触发的。在这个示例中,咱们已经建立了一个HttpModule和HttpHandler,而且也在全部的事件中经过添加自定义逻辑代码展现了一个简单的响应。
下面是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>") ; } } }
下面是HttpHandler类的一个代码片断,它跟踪了ProcessRequest事件。
public class clsHttpHandler : IHttpHandler { public void ProcessRequest(HttpContext context) { clsHttpModule.objArrayList.Add("HttpHandler:ProcessRequest"); context.Response.Redirect("Default.aspx"); } }
同上,咱们也能够跟踪来自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"); } }
下图则显示了上面咱们所讨论的全部事件的执行顺序。
图7 示例结果—事件的执行次序
在上面的部分中,咱们已经了解了一个ASP.NET页面请求事件的总体流程。那么,在其中一个最重要的部分就是ASP.NET页面,可是咱们并无对其进行详细讨论。所以,咱们在此深刻地了解一下ASP.NET页面事件。
每个ASP.NET页都有2个部分:一个是在浏览器中进行显示的部分,它包含了HTML标签、viewstate形式的隐藏域 以及 在HTML input中的数据。当这个页面被提交到服务器时,这些HTML标签会被建立到ASP.NET控件,而且viewstate还会和表单数据绑定在一块儿。一旦你在后置代码中获得全部的服务器控件,你能够执行和写入你本身的逻辑并呈现给客户浏览器。
图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 | 任何你想作的清理工做均可以在这里执行。 |
图9 ASP.NET Page事件流程
(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