首先我们通过在Global.asax中的Application_Start将路由信息注册到RouteTable的Routes静态属性中。如下代码所示:
public class RouteTable { //省略 public static RouteCollection Routes { get; } } protected void Application_Start() { RouteConfig.RegisterRoutes(RouteTable.Routes); } public static void RegisterRoutes(RouteCollection routes) { routes.IgnoreRoute("{resource}.axd/{*pathInfo}"); routes.MapRoute( name: "Default", url: "{controller}/{action}/{id}", defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional } ); } //MapRoute有多个重载,最终实例如下 public static Route MapRoute(this RouteCollection routes, string name, string url, object defaults, object constraints, string[] namespaces) { //省略 Route route = new Route(url, new MvcRouteHandler()) { Defaults = CreateRouteValueDictionaryUncached(defaults), Constraints = CreateRouteValueDictionaryUncached(constraints), DataTokens = new RouteValueDictionary() }; ConstraintValidation.Validate(route); if ((namespaces != null) && (namespaces.Length > 0)) { route.DataTokens[RouteDataTokenKeys.Namespaces] = namespaces; } routes.Add(name, route); return route; }
在new Route对象的同时,我们同时new了一个MvcRouteHandler对象实例传进去。然后将route添加到RouteTable的静态属性RouteCollection中,同时返回该route实例。路由注册完毕。
MVC通过在IHttpModule的实现类UrlRoutingModule的Init方法中拦截HttpApplication的PostResolveRequestCache事件来处理请求。代码如下:
public class UrlRoutingModule : IHttpModule { public RouteCollection RouteCollection { get { if (this._routeCollection == null) { this._routeCollection = RouteTable.Routes; } return this._routeCollection; } set { this._routeCollection = value; } } protected virtual void Init(HttpApplication application) { //省略 application.PostResolveRequestCache += new EventHandler(this.OnApplicationPostResolveRequestCache); } private void OnApplicationPostResolveRequestCache(object sender, EventArgs e) { HttpApplication httpApplication = (HttpApplication)sender; HttpContextBase context = new HttpContextWrapper(httpApplication.Context); this.PostResolveRequestCache(context); } public virtual void PostResolveRequestCache(HttpContextBase context) { RouteData routeData = this.RouteCollection.GetRouteData(context); //省略 IRouteHandler routeHandler = routeData.RouteHandler; //省略 RequestContext requestContext = new RequestContext(context, routeData); context.Request.RequestContext = requestContext; IHttpHandler httpHandler = routeHandler.GetHttpHandler(requestContext); //省略 if (!(httpHandler is UrlAuthFailureHandler)) { context.RemapHandler(httpHandler); return; } //省略 } }
插一句,UrlRoutingModule中的RouteCollection默认来自对RouteTable的静态属性Routes的引用。
拦截之后,通过RouteCollection的GetRouteData获得相应的路由数据RouteData的实例routeData。routeData有一个属性RouteHandler,在注册路由时,实例化Route时,我们实例化了一个MvcRouteHandler给构造函数,这里RouteHandler属性其实MvcRouteHandler的实例引用(如下代码片段中的Route)。
然后我们routeHandler是的GetHttpHandler方法,获取到IHttpHandler(如下代码片段中的MvcRouteHandler 类)。
//代码片段三 public class Route : RouteBase { //省略 public IRouteHandler RouteHandler { get; set; } public string Url { get { return this._url ?? string.Empty; } set { this._parsedRoute = RouteParser.Parse(value); this._url = value; } } public Route(string url, IRouteHandler routeHandler) { this.Url = url; this.RouteHandler = routeHandler; } public override RouteData GetRouteData(HttpContextBase httpContext) { string virtualPath = httpContext.Request.AppRelativeCurrentExecutionFilePath.Substring(2) + httpContext.Request.PathInfo; RouteValueDictionary routeValueDictionary = this._parsedRoute.Match(virtualPath, this.Defaults); if (routeValueDictionary == null) { return null; } RouteData routeData = new RouteData(this, this.RouteHandler); if (!this.ProcessConstraints(httpContext, routeValueDictionary, RouteDirection.IncomingRequest)) { return null; } foreach (KeyValuePair<string, object> current in routeValueDictionary) { routeData.Values.Add(current.Key, current.Value); } if (this.DataTokens != null) { foreach (KeyValuePair<string, object> current2 in this.DataTokens) { routeData.DataTokens[current2.Key] = current2.Value; } } return routeData; } //省略 } public class MvcRouteHandler : IRouteHandler { //省略 protected virtual IHttpHandler GetHttpHandler(RequestContext requestContext) { requestContext.HttpContext.SetSessionStateBehavior(GetSessionStateBehavior(requestContext)); return new MvcHandler(requestContext); } //省略 }