如我们所料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对象,源码如下:
  [TypeForwardedFrom("System.Web.Routing, Version=3.5.0.0, Culture=Neutral, PublicKeyToken=31bf3856ad364e35")]
  public interface IRouteHandler
  {
  // Methods
  IHttpHandler GetHttpHandler(RequestContext requestContext);
  }
  到这里我们的疑问解开了,原来我们注册的路由规则都实例化成了Route对象,Route的GetRouteData方法用来匹配路由(参考博客园大神Artech的书籍),路由规则中的physicalFile和checkPhysicalUrlAccess用来实例化一个IHttpHandler实例,用来处理请求。
  总结:ASP.NET的路由模型如下图所示