开篇:上一篇我们了解了一个ASP.Net页面请求的核心处理入口,它经历了三个重要的入口,分别是:ISAPIRuntime.ProcessRequest()、HttpRuntime.ProcessRequest()以及HttpApplication.Init()。其中,在HttpApplication的Init()方法中触发了请求处理管道事件的执行,本篇我们就来看看所谓的请求处理管道。
(1)Part 1:前奏
(2)Part 2:核心
(3)Part 3:管道
(4)Part 4:WebForm页面生命周期
(5)Part 5:MVC页面声命周期
HttpApplication对象是ASP.NET中处理请求的重要对象,但是,这种类型的对象实例不是由程序员来创建的,而是由ASP.NET帮助我们创建的。为了便于扩展处理工作,HttpApplication采用处理管道的方法进行处理,将处理的过程分为多个步骤,每个步骤通过事件的形式暴露给程序员,这些事件按照固定的处理顺序依次触发,程序员通过编写事件处理方法就可以自定义每一个请求的扩展处理过程。
①传说中的19个事件
对于HttpApplication来说,到ASP.NET 4.0版本,提供了19个重要的标准事件,如下图所示:
在整个请求处理管道中,HttpContext上下文被依次传输到各个处理事件中,由不同的处理单元(HttpModule、HttpHandler、Page等)进行处理。从这里可以看出,ASP.NET请求处理管道就像是一个大型的AOP框架。
②HttpModule与HttpHandler
在进一步深入了解之前,让我们先来了解一下什么是HttpModule和HttpHandlers。他们帮助我们在ASP.NET页面处理过程的前后注入自定义的逻辑处理。他们之间主要的差别在于:
- 如果你想要注入的逻辑是基于像'.aspx','.html'这样的扩展文件,那么你可以使用HttpHandler。换句话说,HttpHandler是一个基于处理器的扩展。
- HttpHandler总结:在ASP.NET WebForm中,无论是一般处理程序还是WebPage都实现了IHttpHandler接口,而ASP.NET MVC中也有MvcHandler实现了IHttpHandler接口;
- 如果你想要在ASP.NET管道事件中注入逻辑,那么你可以使用HttpModule。也可以说,HttpModule是一个基于处理器的事件。
- HttpModule总结:刚刚我们说到ASP.NET请求处理管道就像是一个大型的AOP框架,因此我们可以借助HttpModule自定义地注册或移除一些事件逻辑,以完成我们想要的效果。ASP.NET默认实现了针对WebForm和MVC的HttpModule,像ASP.NET MVC中默认使用的是UrlRoutingModule。具体实现方式是:通过改写Global文件或自定义一个实现IHttpModule接口的类并在Web.config中进行注册。
-
<?xml version="1.0"?> <configuration> <system.web> <httpModules> <add name="myHttpModule" type="FirstModule"/> </httpModules> </system.web> </configuration>
public class FirstModule : IHttpModule { public void Dispose() { throw new NotImplementedException(); } public void Init(HttpApplication context) { context.BeginRequest += new EventHandler(context_BeginRequest); } void context_BeginRequest(object sender, EventArgs e) { HttpApplication application = sender as HttpApplication; application.Context.Response.Write("第三方过滤器:哇哈哈!"); } }
③19个事件中我们可以做些什么?
一个十分有价值的问题就是在什么事件中我们又可以做些什么?下表就展示了这个问题的答案:
| 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页面且可以用来: 1、动态地创建控件,如果你一定要在运行时创建控件; 2、任何初始化设置 3、母版页及其设置 在这部分中我们没有获得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>") ; } } }