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






4.92/5 (396投票s)
ASP.NET 应用程序和页面生命周期
目录
引言
在本文中,我们将尝试理解从用户发送请求到请求在浏览器上呈现的整个过程中发生的各种事件。因此,我们将首先尝试理解 ASP.NET 请求的两个更广泛的步骤,然后我们将深入了解“HttpHandler
”、“HttpModule
”和 ASP.NET 页面对象发出的各种事件。随着我们在这趟事件之旅中深入,我们将尝试理解每种事件应该执行什么样的逻辑。
两步过程
从 30,000 英尺的高度来看,ASP.NET 请求处理是一个 2 步过程,如下所示。用户向 IIS 发送请求
- ASP.NET 创建一个可以处理请求的环境。换句话说,它创建应用程序对象、请求、响应和上下文对象来处理请求。
- 一旦环境创建完毕,请求将通过一系列由模块、处理程序和页面对象处理的事件进行处理。简而言之,我们将此步骤命名为 MHPM(模块、处理程序、页面和模块事件),稍后我们将详细介绍。
在接下来的章节中,我们将更详细地了解这两个主要步骤。
ASP.NET 环境的创建
步骤 1: 用户向 IIS 发送请求。IIS 首先检查哪个 ISAPI 扩展可以处理此请求。根据文件扩展名处理请求。例如,如果页面是“.ASPX 页面”,那么它将被传递给‘aspnet_isapi.dll’进行处理。
步骤 2: 如果这是网站的第一个请求,那么一个名为‘ApplicationManager
’的类将创建一个应用程序域,网站可以在其中运行。正如我们所知,应用程序域在托管在同一 IIS 上的两个 Web 应用程序之间创建隔离。因此,如果一个应用程序域出现问题,它不会影响其他应用程序域。
步骤 3: 新创建的应用程序域创建托管环境,即‘HttpRuntime
’对象。一旦托管环境创建完毕,必要的核心 ASP.NET 对象,如‘HttpContext
’、‘HttpRequest
’和‘HttpResponse
’对象就会被创建。
步骤 4: 一旦所有核心 ASP.NET 对象都创建完毕,‘HttpApplication
’对象就会被创建来处理请求。如果您系统中有‘global.asax’文件,那么‘global.asax’文件的对象将被创建。请注意,global.asax 文件继承自‘HttpApplication
’类。
注意:首次将 ASP.NET 页面附加到应用程序时,会创建一个新的‘HttpApplication
’实例。为了最大化性能,HttpApplication
实例可能会被重复用于多个请求。
步骤 5: 然后将HttpApplication
对象分配给核心 ASP.NET 对象来处理页面。
步骤 6: HttpApplication
然后通过 HTTP 模块事件、处理程序和页面事件开始处理请求。它会触发 MHPM 事件以进行请求处理。
注意:有关更多详细信息,请阅读此内容。
下图解释了 ASP.NET 请求的内部对象模型是什么样的。顶层是 ASP.NET 运行时,它创建一个‘Appdomain
’,其中包含带有‘request’、‘response’和‘context’对象的‘HttpRuntime
’。
通过触发的 MHPM 事件处理请求
一旦创建了‘HttpApplication
’,它就开始处理请求。它会经过 3 个不同的部分:‘HttpModule
’、‘Page
’和‘HttpHandler
’。当它经过这些部分时,它会调用不同的事件,开发人员可以扩展这些事件并添加自定义逻辑。
在我们继续之前,让我们了解一下‘HttpModule
’和‘HttpHandlers
’是什么。它们帮助我们在 ASP.NET 页面处理之前和之后注入自定义逻辑。两者之间的主要区别是
- 如果您想根据文件扩展名(如‘.ASPX’、‘.HTML’)注入逻辑,则使用‘
HttpHandler
’。换句话说,‘HttpHandler
’是一个基于扩展名的处理器。 - 如果您想在 ASP.NET 管道的事件中注入逻辑,则使用‘
HttpModule
’。ASP.NET。换句话说,‘HttpModule
’是一个基于事件的处理器。
您可以从这里阅读更多关于它们之间差异的信息。
下面是请求处理的逻辑流程。有 4 个重要的步骤 MHPM,如下所述
步骤 1(M:HttpModule): 客户端请求处理开始。在 ASP.NET 引擎创建 ASP.NET HttpModule
之前,它会发出可以用来注入自定义逻辑的事件。在您的页面对象创建之前,有 6 个重要事件可以利用:BeginRequest
、AuthenticateRequest
、AuthorizeRequest
、ResolveRequestCache
、AcquireRequestState
和 PreRequestHandlerExecute
。
步骤 2(H:‘HttpHandler’): 一旦触发了上述 6 个事件,ASP.NET 引擎将调用 ProcessRequest
事件,如果您在项目中实现了 HttpHandler
的话。
步骤 3(P:ASP.NET 页面): 一旦 HttpHandler
逻辑执行完毕,ASP.NET 页面对象就会被创建。在创建 ASP.NET 页面对象时,会触发许多事件,这些事件可以帮助我们在这些页面事件中编写自定义逻辑。有 6 个重要事件为我们在 ASP.NET 页面中编写逻辑提供了占位符:Init
、Load
、validate
、event
、render
和 unload
。您可以使用 SILVER
这个词来记住这些事件:S – 开始(实际上没有意义,只是构成单词)、I – (Init)、L (Load)、V (Validate)、E (Event) 和 R (Render)。
步骤 4(M:HttpModule): 一旦页面对象执行并从内存中卸载,HttpModule
就会提供页面执行后事件,用于注入自定义后处理逻辑。有 4 个重要的后处理事件:PostRequestHandlerExecute
、ReleaserequestState
、UpdateRequestCache
和 EndRequest
。
下图以图示形式展示了这一点。
在什么事件中做什么?
价值百万美元的问题是,我们应该在哪些事件中做什么?下表显示了在哪些事件中可以放入什么类型的逻辑或代码。
节 | 事件 | 描述 |
HttpModule | BeginRequest | 此事件表示新请求;保证每个请求都会触发此事件。 |
HttpModule | AuthenticateRequest | 此事件表示 ASP.NET 运行时已准备好进行用户身份验证。可以在此处注入任何身份验证代码。 |
HttpModule | AuthorizeRequest | 此事件表示 ASP.NET 运行时已准备好进行用户授权。可以在此处注入任何授权代码。 |
HttpModule | ResolveRequestCache | 在 ASP.NET 中,我们通常使用 outputcache 指令进行缓存。在此事件中,ASP.NET 运行时确定页面是否可以从缓存提供,而不是从头开始加载页面。可以在此处注入任何与缓存相关的活动。 |
HttpModule | AcquireRequestState | 此事件表示 ASP.NET 运行时已准备好获取会话变量。您想对会话变量进行的任何处理。 |
HttpModule | PreRequestHandlerExecute | 在将控件交给 HttpHandler 之前,会触发此事件。在您希望将控件交给处理程序之前,进行任何预处理。 |
HttpHandler | ProcessRequest | Httphandler 逻辑已执行。在此部分,我们将编写需要根据页面扩展名执行的逻辑。 |
页面 | Init | 此事件发生在 ASP.NET 页面中,可用于
在此部分,我们无法访问 viewstate、postedvalues,控件也未初始化。 |
页面 | Load (加载) | 在此部分,ASP.NET 控件已完全加载,您可以在此处编写 UI 操作逻辑或任何其他逻辑。 |
页面 | Validate | 如果您的页面上有验证器,您可以在此处检查它们。 |
Render | 现在是时候将输出发送到浏览器了。如果您想对将发送到浏览器的最终 HTML 进行一些更改,您可以在此处输入 HTML 逻辑。 | |
页面 | Unload | 页面对象已从内存中卸载。 |
HttpModule | PostRequestHandlerExecute | 您想在处理程序执行后注入的任何逻辑。 |
HttpModule | ReleaserequestState | 如果您想保存更新一些状态变量,如会话变量。 |
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 页面的所有事件。
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");
}}
下面是显示,其中所有事件都按照上一节中讨论的顺序排列。
深入了解 ASP.NET 页面事件
在上文中,我们已经看到了 ASP.NET 页面请求的事件的总体流程。其中最重要的部分之一是 ASP.NET 页面,我们没有详细讨论它。因此,让我们在本节中花点时间详细描述 ASP.NET 页面事件。
任何 ASP.NET 页面都有 2 个部分:一个是在浏览器上显示的页面,其中包含 HTML 标签、以 viewstate 形式存在的隐藏值以及 HTML 输入框中的数据。当页面发布时,这些 HTML 标签会转换为 ASP.NET 控件,并将 viewstate 和表单数据一起绑定在服务器上。一旦在后端代码中获得了这些完整的服务器控件,您就可以执行并编写自己的逻辑,然后将页面渲染回浏览器。
现在,在这些 HTML 控件在服务器上作为 ASP.NET 控件上线之间,ASP.NET 页面会发出许多可以用于注入逻辑的事件。根据您要执行的任务/逻辑,我们需要将此逻辑适当地放入那些事件中。
注意:大多数开发人员直接使用 page_load
方法处理所有事情,这并不是一个好主意。因此,无论是填充控件、设置 viewstate、应用主题等,所有这些都发生在 page load 中。因此,如果我们能根据逻辑的性质将逻辑放入正确的事件中,那将使您的代码更加整洁。
序号 | 事件 | 控件初始化 | View state 可用 | 表单数据 可用 | 可以在这里写什么逻辑? |
1 | Init | 否 | 否 | 否 | 注意:您可以通过 ASP.NET 请求对象访问表单数据等,但不能通过服务器控件访问。动态创建控件,如果您有需要在运行时创建的控件。任何设置 |
2 | 加载 view state | 不保证 | 是 | 不保证 | 您可以访问 view state 和任何同步逻辑,您希望将 viewstate 推送到后端代码变量的地方可以在此处完成。 |
3 | PostBackdata | 不保证 | 是 | 是 | 您可以访问表单数据。任何您希望将表单数据推送到后端代码变量的逻辑都可以在此处完成。 |
4 | Load (加载) | 是 | 是 | 是 | 这是您将放置任何您想在控件上执行的逻辑的地方。例如,从数据库填充组合框、在网格中排序数据等。在此事件中,我们可以访问所有控件、viewstate 及其发布的 istance。 |
5 | Validate | 是 | 是 | 是 | 如果您的页面有验证器或您想为您的页面执行验证,这里是正确的地方。 |
6 | 事件 | 是 | 是 | 是 | 如果这是通过按钮单击或下拉列表更改的 post back,那么将触发相关的事件。此处可以执行任何与该事件相关的逻辑。 |
7 | Pre-render | 是 | 是 | 是 | 如果您想在将这些控件保存到 view state 之前对 UI 对象进行最终更改,例如更改树结构或属性值。 |
8 | 保存 view state | 是 | 是 | 是 | 在对服务器控件的所有更改完成后,此事件可以作为将控件数据保存到 view state 的机会。 |
9 | Render | 是 | 是 | 是 | 如果您想在输出中添加一些自定义 HTML,这里是您可以这样做的地方。 |
10 | Unload | 是 | 是 | 是 | 您想在此处进行的任何类型的清理。 |
关于源代码
此源代码显示了完整的 ASP.NET 请求周期如何触发。您可以从此处下载。
参考文献
我没有那么聪明能够自己写这篇文章 ;-),很多内容我都是从下面的文章中借鉴的。
- 详细了解 IIS 7.0 生命周期 http://msdn.microsoft.com/en-us/library/bb470252.aspx
- 拦截过滤器 http://msdn.microsoft.com/en-us/library/ms998536.aspx
- 解释如何实现 Httphandlers 和模块 http://msdn.microsoft.com/enus/library/system.web.httpapplication.aspx
- Httphandlers 和 Httpmodules:- http://www.15seconds.com/Issue/020417.htm
- 使用模块和处理程序实现安全性 http://joel.net/articles/asp.net2_security.aspx
- Httpapplication 和 global.asax 之间的区别 http://codebetter.com/blogs/karlseguin/archive/2006/06/12/146356.aspx
Webforms Out - MVC In
ASP.NET Webform 现在已经过时,ASP.NET MVC 是新一代技术。如果您想学习 MVC,可以观看下面的视频,该视频在 16 小时内教会您 ASP.NET MVC。
如需进一步阅读,请观看以下面试准备视频和分步视频系列。