如我们所料UrlRoutingModule实现了IHttpModule接口,我们看看它的Init方法干了些什么?
protected virtual void Init(HttpApplication application) { if (application.Context.Items[_contextKey] == null) { application.Context.Items[_contextKey] = _contextKey; application.PostResolveRequestCache += new EventHandler(this.OnApplicationPostResolveRequestCache); } }
对第7个事件PostResolveRequestCache注册方法OnApplicationPostResolveRequestCache,那么这个方法又是干啥的呢?
public virtual void PostResolveRequestCache(HttpContextBase context) { RouteData routeData = this.RouteCollection.GetRouteData(context);//匹配路由,得到匹配结果RouteData。 if (routeData != null) { IRouteHandler routeHandler = routeData.RouteHandler; if (routeHandler == null) { throw new InvalidOperationException(string.Format(CultureInfo.CurrentCulture, SR.GetString("UrlRoutingModule_NoRouteHandler"), new object[0])); } if (!(routeHandler is StopRoutingHandler)) { RequestContext requestContext = new RequestContext(context, routeData); context.Request.RequestContext = requestContext; IHttpHandler httpHandler = routeHandler.GetHttpHandler(requestContext);//获取处理当前请求的IHttpHandler对象。 if (httpHandler == null) { object[] args = new object[] { routeHandler.GetType() }; throw new InvalidOperationException(string.Format(CultureInfo.CurrentUICulture, SR.GetString("UrlRoutingModule_NoHttpHandler"), args)); } if (httpHandler is UrlAuthFailureHandler) { if (!FormsAuthenticationModule.FormsAuthRequired) { throw new HttpException(0x191, SR.GetString("Assess_Denied_Description3")); } UrlAuthorizationModule.ReportUrlAuthorizationFailure(HttpContext.Current, this); } else { context.RemapHandler(httpHandler);//映射:用当前IHttpHandler对象处理请求。 } } } }
代码已经加了注释,3步走:匹配路由→获取处理当前请求的IHttpHandler对象→映射:用当前IHttpHandler对象处理请求。之后会在第11、12个事件之间调用IHttpHandler对象的PR方法处理当前请求。
我们再整理下思路:ASP.NET先注册了UrlRoutingModule模块,他就是一个实现了IHttpModule接口的类,其Init方法就是在第7个事件上注册一个方法,该方法先匹配路由,如果匹配成功了,则用匹配结果RouteData中的IHttpHandler对象映射到当前上下文中,这样在之后第11、12个事件之间就会调用这个IHttpHandler对象处理请求。
那么问题来了,Route对象是什么时候注入进去的,IHttpHandler对象又是谁?
还记得路由规则是怎么添加的吗?如下面代码所示:
public class Global : System.Web.HttpApplication { protected void Application_Start(object sender, EventArgs e) { var defaults = new RouteValueDictionary(); defaults.Add("name", "*"); //方式一: //通过RouteTable的静态对象Routes新增一个Route类型的对象。 RouteTable.Routes.Add("app", new Route("app/{name}", defaults, new MyRouteHandler())); //方式二: //通过RouteTable的静态对象Routes的扩展方法新增一个路由规则。 RouteTable.Routes.MapPageRoute("default", "app/{name}", "~/WebForm1.aspx", false, defaults); } }
这是我们经常用的两种方式添加路由规则,方式一中有我们自己编写的MyRouteHandler类型的实例作为参数,其实就是通过IRouteHandler接口返回一个IHttpHandler对象。
/// <summary> /// 实现了IRouteHandler接口的类型 /// </summary> internal class MyRouteHandler : IRouteHandler { public IHttpHandler GetHttpHandler(RequestContext requestContext) { //返回一个Page对象,用于处理请求。 return new WebForm1(); } }
其实这两种方式没有本质上的区别,因为方式二中路由规则参数都会实例化一个Route对象的。
我们分析方式二的源代码:
public Route MapPageRoute(string routeName, string routeUrl, string physicalFile, bool checkPhysicalUrlAccess, RouteValueDictionary defaults, RouteValueDictionary constraints, RouteValueDictionary dataTokens) { if (routeUrl == null) { throw new ArgumentNullException("routeUrl"); } Route item = new Route(routeUrl, defaults, constraints, dataTokens, new PageRouteHandler(physicalFile, checkPhysicalUrlAccess)); this.Add(routeName, item); return item; }
发现所有的路由规则参数都用来实例化一个Route对象了,其中参数physicalFile和checkPhysicalUrlAccess用来实例化PageRouteHandler对象了,其源码如下:
public class PageRouteHandler : IRouteHandler { }
这是一个实现了IRouteHandler接口的类型,而这个接口只有一个作用就是返回IHttpHandler对象,源码如下: