前一篇文章我们学习了WebForm开发中页面级事件的注册,今天我们就接着学习另外一种请求过滤机制:管道事件注册
我们知道Application的管道有23个步骤 19个事件
在进一步讲解之前,我们先来了解一下19个管道事件
(1)BeginRequest: 开始处理请求
(2)AuthenticateRequest授权验证请求,获取用户授权信息
(3):PostAuthenticateRequest获取成功
(4): AunthorizeRequest 授权,一般来检查用户是否获得权限
(5):PostAuthorizeRequest:获得授权
(6):ResolveRequestCache:获取页面缓存结果
(7):PostResolveRequestCache 已获取缓存 当前请求映射到MvcHandler(pr): 创建控制器工厂 ,创建控制器,调用action执行,view→response//action Handler : PR()
(8):PostMapRequestHandler 创建页面对象:创建 最终处理当前http请求的 Handler 实例: 第一从HttpContext中获取当前的PR Handler ,Create
(9):PostAcquireRequestState 获取Session
(10)PostAcquireRequestState 获得Session
(11)PreRequestHandlerExecute:准备执行页面对象 执行页面对象的ProcessRequest方法
(12)PostRequestHandlerExecute 执行完页面对象了
(13)ReleaseRequestState 释放请求状态
(14)PostReleaseRequestState 已释放请求状态
(15)UpdateRequestCache 更新缓存
(16)PostUpdateRequestCache 已更新缓存
(17)LogRequest 日志记录
(18)PostLogRequest 已完成日志
(19)EndRequest 完成
这些事件都是可以对请求报文进行处理的,也就是说可以进行过滤操作的。默认的很多事件都是没有注册的,管道流通到这个地方的时候什么都不会执行。但是我们可以通过手动注册管道事件(其实就是给某个事件内部添加代码),实现请求的过滤。
那具体应该怎么操作呢?总的来说有两种方法,下面我们来一一学习。
通过asp.net 的原理我们知道,HttpApplication在对象池中不存在的时候就是通过反射该文件来创建Application对象的,它和Application对象是密切相关的。我们当然也就可以在这个类里面进行管道的事件注册。
该类默认已经为我们注册了下面的一系列事件(但是事件里面都是没有具体实现代码的)
protected void Application_BeginRequest(object sender, EventArgs e) { } protected void Application_AuthenticateRequest(object sender, EventArgs e) { }
在开始我们自己管道事件的注册之前,我们不妨对上面的事件观察一下。
观察上面的命名规则,我们看到方法的名称都是以Application开头。通过上一篇页面级事件注册的学习已经知道, 如果我们想注册管道事件也需要这样操作(默认的已经帮我们把事件与方法关联起来了)
注册管道事件代码如下所示:
protected void Application_BeginRequest(object sender, EventArgs e) { Context.Response.Write("开始处理请求。。。。。。"); } protected void Application_AuthenticateRequest(object sender, EventArgs e) { Context.Response.Write("验证请求。。。。。。"); } protected void Application_PostAuthenticateRequest(object sender, EventArgs e) { Context.Response.Write("获取成功"); } protected void Application_EndRequest(object sender, EventArgs e) { Context.Response.Write("结束请求"); }
运行程序
到请求执行到管道所在的事件的时候就会执行我们在管道里面编写的代码。
public class HttpModule:IHttpModule { public void Dispose() { throw new NotImplementedException(); } //注意 这里传递的是HttpApplication对象 public void Init(HttpApplication context) { // throw new NotImplementedException(); context.BeginRequest += new EventHandler(BeginRequest);//关键点 就是在这里注册事件的 } public void BeginRequest(object sender, EventArgs e) { var context = (sender as HttpApplication).Context; context.Response.Write("这是开始执行请求的事件"); } }同第一种Global方法不同的是, 这种方法需要在创建的类的Init()方法中显示绑定事件和方法。
程序执行的时候会读取配置信息,我们可以在配置里面添加内容来告诉应用程序一些信息。
在Web.config配置文件中添加管道节点,如下所示
<httpModules> <add name="HttpModule" type="WebApplication1.HttpModule"/>--一定要是全名称(命名空间+类名) </httpModules>
我们可以添加多个管道 (其实感觉这没必要,因为我们完全可以在一个管道的Init()方法中注册多个事件),不需要的话直接注释掉就可以了,这里也是体现了管道很好的插件机制。
到这里,不知道你有没有疑问产生。第一种方法,我们之所以可以在Global.asax文件中注册管道是因为我们创建HttpApplication对象的时候会根据Global文件反射出一个实例出来。那么,我们第二种方式又是在哪里体现我们确实是实现了管道事件的注册呢?
其实,通过ApplicationFactory创建的Application 对象,在创建完Application之后会调用Application对象的初始化方法。在Application的初始化内部会读取配置文件,读取所有的HttpModule并放到一个ModuleCollection管道集合中去,最后循环遍历这个集合中每个管道的Init()方法,这样就完成了所有管道事件的注册。注意,这里只是完成了管道事件的注册。
Ok,运行程序,看看效果
OK,两种管道事件的注册方法讲解完毕。
下面我们模拟一下管道的执行,加深对管道的了解。
通过对asp.net原理的了解,我们知道请求交给HttpRuntime之后,会调用HttpRuntime的ProcessRequest()方法,那在该方法的内部具体执行了什么呢?
下面的代码对这个过程进行了大致模拟。
定义HttpApplication类
对上面的代码做个总结:
IsapiRuntime.dll会调用它的ProcessRequest()方法,这个方法内有一个ecb句柄(存放着请求报文的内容)。在这个方法内部,会根据这个句柄创建一个HttpWorkRequest对象。HttpRutime的ProcssRequest()方法会以上面创建的HttpWorkRequest对象为参数,创建HttpContext。接着会根据HttpApplication或Global.cs文件创建出一个HttpApplication对象并进行HttpApplication对象的初始化操作(在这个初始化操作过程中会读取配置文件,也就是上面第二种管道事件注册的核心思想)。接着再执行HttpApplication对象的ProcessRequest()方法,在这个方法的内部会进行管道事件的执行以及aspx请求页面声明周期的执行。
Ok,asp.net 的管道流通大概就是这样,不知道讲解的够不够请求,如果你对asp.net原理有疑问,欢迎参考我的另一篇文章:asp.net 的原理