Asp.net MVC Route初探

Asp.net MVC天生就有着漂亮的Url.但是却有别于Asp.net的UrlRewriter.那么其的实现原理是怎样的呢?这就要说到Route了.

Asp.Net MVC生命周期

Asp.net MVC的生命周期由8个步骤组成:

1.RouteTable(路由表)的创建

2.UrlRoutingMoudle请求拦截

3.Routing engine确定route

4.RouteHandler创建相关的IHttpHandler实例

5.IHttpHandler实例确定Controller(控制器)

6.Controller执行

7.视图引擎创建

8.视图呈现

这里主要讲解前4个.

RouteTable(路由表)的创建

打开Global.asax

   1: public class MvcApplication : System.Web.HttpApplication
   2:    {
   3:        public static void RegisterRoutes(RouteCollection routes)
   4:        {
   5:            routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
   6:  
   7:            routes.MapRoute(
   8:                "Default", // Route name
   9:                "{controller}/{action}/{id}", // URL with parameters
  10:                new { controller = "Home", action = "Index", id = UrlParameter.Optional }, // Parameter defaults
  11:                new { controller = @"[^\.]*"}
  12:            );
  13:  
  14:            routes.MapRoute(
  15:                "Defalut",
  16:                "{controller}/Blog/{date}",
  17:                new {  action = "Blog" },
  18:                new { date = @"^\d{4}\.\d{2}\.\d{2}" }
  19:                );
  20:        }
  21:  
  22:        protected void Application_Start()
  23:        {
  24:            AreaRegistration.RegisterAllAreas();
  25:  
  26:            RegisterRoutes(RouteTable.Routes);
  27:  
  28:            //RouteDebug.RouteDebugger.RewriteRoutesForTesting(RouteTable.Routes);
  29:        }
  30:    }

在此,我们声明了两个Route.

在MVC1中.我们必须

   1: routes.Add(new Route("User/Login", new RouteValueDictionary(new { controller = "User", action = "Login" }), new MvcRouteHandler()));
   2:            routes.Add(new Route("User/Logout", new RouteValueDictionary(new { controller = "User", action = "Logout" }), new MvcRouteHandler()));
   3:            routes.Add(new Route("User/Signup", new RouteValueDictionary(new { controller = "User", action = "Signup" }), new MvcRouteHandler()));

 

这样添加.但在.Net3.5中.我们却可以直接利用匿名类直接New一个.这是因为.Net3.5中扩展了一个MapRoute方法.该方法利用反射.进行背后的添加

   1: public static Route MapRoute(this RouteCollection routes, string name, string url, object defaults, object constraints, string[] namespaces) {
   2:             if (routes == null) {
   3:                 throw new ArgumentNullException("routes");
   4:             }
   5:             if (url == null) {
   6:                 throw new ArgumentNullException("url");
   7:             }
   8:  
   9:             Route route = new Route(url, new MvcRouteHandler()) {
  10:                 Defaults = new RouteValueDictionary(defaults),
  11:                 Constraints = new RouteValueDictionary(constraints),
  12:                 DataTokens = new RouteValueDictionary()
  13:             };
  14:  
  15:             if ((namespaces != null) && (namespaces.Length > 0)) {
  16:                 route.DataTokens["Namespaces"] = namespaces;
  17:             }
  18:  
  19:             routes.Add(name, route);
  20:  
  21:             return route;
  22:         }

 

UrlRoutingMoudle请求拦截

按照MS惯例,一般会在WebConfig留下些蛛丝马迹,打开WebConfig.不出其然.我们发现HttpMoudle中有

   1: <add name="UrlRoutingModule" type="System.Web.Routing.UrlRoutingModule, System.Web.Routing, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35"/>

利用Reflector打开UrlRoutingModule类.

   1: protected virtual void Init(HttpApplication application)
   2: {
   3:     application.PostResolveRequestCache += new EventHandler(this.OnApplicationPostResolveRequestCache);
   4:     application.PostMapRequestHandler += new EventHandler(this.OnApplicationPostMapRequestHandler);
   5: }
   6:  
   7:  

Routing engine确定route

可以看到.在application的events中注册了PostResolveRequestCache 和PostMapRequestHandler 事件.

PostResolveRequestCache

   1: public virtual void PostResolveRequestCache(HttpContextBase context)
   2: {
   3:     RouteData routeData = this.RouteCollection.GetRouteData(context);
   4:     if (routeData != null)
   5:     {
   6:         IRouteHandler routeHandler = routeData.RouteHandler;
   7:         if (routeHandler == null)
   8:         {
   9:             throw new InvalidOperationException(string.Format(CultureInfo.CurrentUICulture, RoutingResources.UrlRoutingModule_NoRouteHandler, new object[0]));
  10:         }
  11:         if (!(routeHandler is StopRoutingHandler))
  12:         {
  13:             RequestContext requestContext = new RequestContext(context, routeData);
  14:             IHttpHandler httpHandler = routeHandler.GetHttpHandler(requestContext);
  15:             if (httpHandler == null)
  16:             {
  17:                 throw new InvalidOperationException(string.Format(CultureInfo.CurrentUICulture, RoutingResources.UrlRoutingModule_NoHttpHandler, new object[] { routeHandler.GetType() }));
  18:             }
  19:             context.Items[_requestDataKey] = new RequestData { OriginalPath = context.Request.Path, HttpHandler = httpHandler };
  20:             context.RewritePath("~/UrlRouting.axd");
  21:         }
  22:     }
  23: }
  24:  
  25:  

这里.首先通过RouteCollection.GetRouteData得到当前的RouteData,

UrlRoutingModule.RouteCollection

   1: public RouteCollection RouteCollection
   2: {
   3:     get
   4:     {
   5:         if (this._routeCollection == null)
   6:         {
   7:             this._routeCollection = RouteTable.Routes;
   8:         }
   9:         return this._routeCollection;
  10:     }
  11:     set
  12:     {
  13:         this._routeCollection = value;
  14:     }
  15: }
  16:  

module中的RouteCollection只是很简单的引用了RouteTable中的静态实例Routes而已.

RouteTable

   1: public class RouteTable
   2: {
   3:     // Fields
   4:     private static RouteCollection _instance = new RouteCollection();
   5:  
   6:     // Properties
   7:     public static RouteCollection Routes
   8:     {
   9:         get
  10:         {
  11:             return _instance;
  12:         }
  13:     }
  14: }

RouteCollection.GetRouteData

这是获取RouteDate的核心实现.

   1: public RouteData GetRouteData(HttpContextBase httpContext)
   2: {
   3:     if (httpContext == null)
   4:     {
   5:         throw new ArgumentNullException("httpContext");
   6:     }
   7:     if (httpContext.Request == null)
   8:     {
   9:         throw new ArgumentException(RoutingResources.RouteTable_ContextMissingRequest, "httpContext");
  10:     }
  11:     if (!this.RouteExistingFiles)
  12:     {
  13:         string appRelativeCurrentExecutionFilePath = httpContext.Request.AppRelativeCurrentExecutionFilePath;
  14:         if (((appRelativeCurrentExecutionFilePath != "~/") && (this._vpp != null)) && (this._vpp.FileExists(appRelativeCurrentExecutionFilePath) || this._vpp.DirectoryExists(appRelativeCurrentExecutionFilePath)))
  15:         {
  16:             return null;
  17:         }
  18:     }
  19:     using (this.GetReadLock())//线程锁
  20:     {
  21:         foreach (RouteBase base2 in this)//遍历当前集合中的所有RouteBase
  22:         {
  23:             RouteData routeData = base2.GetRouteData(httpContext); //调用RouteBase的RouteData.此处传入的Class是Route.
  24:             if (routeData != null)
  25:             {
  26:                 return routeData;
  27:             }
  28:         }
  29:     }
  30:     return null;
  31: }
  32:  

Route

Route继承至RouteBase.Route中提供了MVC的Route信息.

可以看到最后承载Route数据的容器是RouteVallueDictionary.Route中包含了该Dictionary

RouteData

RouteData的实现很简单.就提供了几个基本的字段而已.主要用于描述当前Route数据的信息.如此一来.我们可以得到当前Url所匹配的Route.

   1: public class RouteData
   2: {
   3:     // Fields
   4:     private RouteValueDictionary _dataTokens;
   5:     private IRouteHandler _routeHandler;
   6:     private RouteValueDictionary _values;
   7:  
   8:     // Methods
   9:     public RouteData();
  10:     public RouteData(RouteBase route, IRouteHandler routeHandler);
  11:     public string GetRequiredString(string valueName);
  12:  
  13:     // Properties
  14:     public RouteValueDictionary DataTokens { get; }
  15:     public RouteBase Route { get; set; }
  16:     public IRouteHandler RouteHandler { get; set; }
  17:     public RouteValueDictionary Values { get; }
  18: }

RouteHandler创建相关的IHttpHandler实例

RouteHandler

得到RouteData之后.获取RouteData之中的RouteHandler.根据RouteHandler获取相关的IHttpHandler.这样.MVC的Route隐射阶段就已经完成

   1: RequestContext requestContext = new RequestContext(context, routeData);
   2: IHttpHandler httpHandler = routeHandler.GetHttpHandler(requestContext);

 

后面就是Controller的确定和执行了.

posted @ 2010-09-05 20:50  skinsen  Views(2388)  Comments(0Edit  收藏  举报