从请求管道深入剖析HttpModule的实现机制,有图有真相
想要了解底层的原理必须对请求处理过程和页面的生命周期有点了解才方便您入门学习一下内容:
关于请求处理过程和页面的生命周期将会在接下来的日子为大家做一个深入的讲解。
HttpModule的实现机制如下:
1.请求到达ISAPIRuntime 的时候通过ProcessReqeust(下文统称pr ) 方法创建 HttpWrokRequest 对象。
2.在执行ISAPIRuntime 的pr 方法时候,方法内部的HttpRuntime 的pr 方法根据HttpWorkRequest 对象创建了上下文对象 HttpContext 。
3.在HttpRuntime 的 pr 方法内部又通过 HttpApplicationFactory 创建了一个处理应用程序的 HttpApplication 实例。
注意:HttpApplication的创建是根据Global.asax文件编译后的类型,再通过反射的方法创建的实例,由于创建实例的过程非常消耗时间和资源,这个则使用了对象池技术
4.在创建HttpApplication 实例的过程中,内部会调用InitInternal 方法,在这个方法里面 调用了HttpModule 的初始化方法,实现了事件的注册。
注意:在实现事件的注册的过程中,内部会去配置文件里面找是否有配置HttpModule模块,如果有则通过反射注册,没有则继续往下走,直到方法跳出。这个过程就是微软的插件机制的体现。
5.事件注册完之后,HttpApplication实例则开始调用自己的pr 方法开始执行页面的生命周期了。
总结:HttpModule 模块的事件注册,就是在HttpApplication 实例内部调用InitInternal 方法,这个方法里面 调用了HttpModule 的初始化方法,实现了事件的注册。
下面的代码是帮助你理解这个过程:
1、首先定义一个上下文 类 HttpContext
1 using System; 2 using System.Collections.Generic; 3 using System.Linq; 4 using System.Text; 5 6 namespace HttpApplicationProcessMethodDemo 7 { 8 /// <summary> 9 /// 上下文 10 /// </summary> 11 public class HttpContext 12 { 13 } 14 }
2.定义两个接口分别为: IHttpHandler 、IHttpModule
using System; using System.Collections.Generic; using System.Linq; using System.Text; namespace HttpApplicationProcessMethodDemo { /// <summary> /// 接口,这个接口主要是在application调用pr方法的时候 /// 实现调用具体页面或一般处理程序的pr方法的。 /// </summary> public interface IHttpHandler { void ProcessRequest(HttpContext context); } }
using System; using System.Collections.Generic; using System.Linq; using System.Text; namespace HttpApplicationProcessMethodDemo { /// <summary> /// 接口,这个接口主要模拟在Application 的 InitInternal方法内部实现事件的注册 /// </summary> public interface IHttpModule { void Init(HttpApplication application); } }
3、定义一个页面类 Page
using System; using System.Collections.Generic; using System.Linq; using System.Text; namespace HttpApplicationProcessMethodDemo { /// <summary> /// 页面类 /// </summary> public class Page:IHttpHandler { /// <summary> /// 实现了IHttpHandler接口 /// </summary> /// <param name="context">上下文</param> public void ProcessRequest(HttpContext context) { Console.WriteLine("页面的生命周期...."); Console.WriteLine(".................."); Console.WriteLine(".................."); Console.WriteLine(".................."); Console.WriteLine("页面的生命周期结束..."); } } }
4.定义一个应用程序类 Application
using System; using System.Collections.Generic; using System.Linq; using System.Text; namespace HttpApplicationProcessMethodDemo { public class HttpApplication:IHttpHandler { //初始化方法 public void InitInternal() { //从配置文件中读取所有的注册了HttpModule的程序集,然后通过反射出实例,并调用Init方法!!! 下面的MyHttpModule假设是通过反射出来的 IHttpModule httpModule = new MyHttpModule(); httpModule.Init(this); BindEvent(); } //Application 自己的事件响应方法 private void BindEvent() { BeginRequest += new EventHandler(HttpApplication_BeginRequest); PostResolveRequestCache += new EventHandler(HttpApplication_PostResolveRequestCache); EndRequest += new EventHandler(HttpApplication_EndRequest); } void HttpApplication_EndRequest(object sender, EventArgs e) { Console.WriteLine("application自己的事件响应方法执行了--EndRequest"); } void HttpApplication_PostResolveRequestCache(object sender, EventArgs e) { Console.WriteLine("application自己的事件响应方法执行了--PostResolveRequest"); } void HttpApplication_BeginRequest(object sender, EventArgs e) { Console.WriteLine("application自己的事件响应方法执行了--BeginRequest"); } //把此方法看成是 http 请求处理的管道 public void ProcessRequest(HttpContext context) { //19个事件,23个步骤 Console.WriteLine("开始请求"); //触发第一个事件 BeginRequest(this, null); //触发第七个事件 PostResolveRequestCache(this, null); Console.WriteLine("已经获取缓存"); //第七个和第八个事件之间,创建页面对象或一般处理程序 IHttpHandler httpHandler = new Page(); Console.WriteLine("创建页面对象"); //在11 和 12 个事件之间执行pr方法 Console.WriteLine("开始执行页面的生命周期"); httpHandler.ProcessRequest(context); //最后一个事件 EndRequest(this, null); Console.WriteLine("结束请求"); } public event EventHandler BeginRequest; public event EventHandler PostResolveRequestCache; public event EventHandler EndRequest; } }
5.模拟请求管道中的执行过程
using System; using System.Collections.Generic; using System.Linq; using System.Text; namespace HttpApplicationProcessMethodDemo { class Program { static void Main(string[] args) { //ISAPIRuntime //假设根据请求创建了HttpContext上下文 HttpContext context = new HttpContext(); //假设从HttpApplicationFactory创建出来 HttpApplication application = new HttpApplication(); //把所有注册在配置文件中的HttpModule加载并执行其Init方法 application.InitInternal(); //调用pr方法开始执行页面的pr方法 application.ProcessRequest(context); Console.ReadKey(); } } }
6.自定义一个HttpModule
using System; using System.Collections.Generic; using System.Linq; using System.Text; namespace HttpApplicationProcessMethodDemo { /// <summary> /// 自定义的HttpModule模块 /// </summary> public class MyHttpModule : IHttpModule { /// <summary> /// 实现了IHttpModule接口 /// </summary> /// <param name="application"></param> public void Init(HttpApplication application) { //注册事件 application.BeginRequest += new EventHandler(application_BeginRequest); application.PostResolveRequestCache += new EventHandler(application_PostResolveRequestCache); application.EndRequest += new EventHandler(application_EndRequest); } void application_EndRequest(object sender, EventArgs e) { Console.WriteLine("HttpModule注册了EndRequest方法"); } void application_PostResolveRequestCache(object sender, EventArgs e) { Console.WriteLine("HttpModule注册了PostResolveRequestCache方法"); } void application_BeginRequest(object sender, EventArgs e) { Console.WriteLine("HttpModule注册了BeginRequest方法"); } } }
通过以上的步骤就实现了整个管道的执行过程和HttpModule的实现原理了。
下面是效果图: