蜿蜒的管线
关于系列的第二篇,在管线与路由之间犹豫了很久,最终选择了管线—为免于盲人摸象的困惑。
管线的位置在哪里呢?webform,mvc以及web api都架构于asp.net平台上,管线则是asp.net的中枢。
获取管线,其实就是获取HttpApplication的事件(.net版本不同,管线的组成也不一样)
public void LinePile()
{
foreach (var ev in typeof(HttpApplication).GetEvents()) {
Response.Write(ev.Name);
Response.Write("<br />");
}
}
得到的结果如下
图中可以很明显的看到从BeginRequest到EndRequest的管线过程,各个管道过程的名字也很清楚的示意出了它的作用。asp.net中关键对象之一的HttpModule就是通过订阅这些管线阶段达到功能注入的目的。在使用管线的时候一定要注意阶段的选择。下面有一段从URLRoutingModule中抽出的代码:
1 protected virtual void Init(HttpApplication application) 2 { 3 if (application.Context.Items[_contextKey] == null) 4 { 5 application.Context.Items[_contextKey] = _contextKey; 6 application.PostResolveRequestCache += new EventHandler(this.OnApplicationPostResolveRequestCache); 7 } 8 }
代码很清晰的表明,路由导航模块注册了PostResolvRequestCache管线事件,具体的事件过程等到讲路由的时候再做具体的分析,只要知道正是在这个事件中路由系统查找路由表并试图得到最终执行的IHttpHandler。既然在PostResolvRequestCache事件中IHttphandler可能被设定,那么执行阶段又在那里呢,注意看管线的PreRequestHandlerExcute与PostRequestHandlerExcute事件,Excute事件就在二者之间执行。所以如果你想使用Application_xx事件或者模块去指定IHttpHandler请一定要在PreRequestHandlerExcute事件之前完成。
对管线的干预有两种方式,即Application_事件名称和模块,二者的区别在模块化。下面的代码显示了注册的模块
1 public void Modules() { 2 foreach (var md in HttpContext.ApplicationInstance.Modules) { 3 Response.Write(md); 4 Response.Write("<br />"); 5 } 6 }
结果如下:
熟悉的名称是不是很多?
管线由HttpApplication驱动,通过对不同管线事件的订阅,可以将不同的功能注入进去,上面的代码已经证明我们所熟知的Cache、Session等对象都是通过管线注入实现。对每一个进入的请求,管线的执行是必须的,但管线本身却可以跳跃—通过调用Request.End(),它在内部调用HttpApplication的CompleteRequest方法,这将直接抵达管线的EndRequest阶段。