zoukankan      html  css  js  c++  java
  • 灵活的路由(上)

    灵活的路由(上)

    在上一篇关于管线的随笔中已经提及了管线,通过对管线的分析,我们可以得到下面几个结论:路由系统由URLRoutingModule模块实现,它订阅了PostResolvRequestCache事件;路由系统通过查阅路由并尽可能的通过RemapHandler方法,确定excuteHandler阶段执行的IHttphandler。这一篇随笔想详细谢谢路由的定义、注册和导航的具体过程。

      路由系统的导航过程定义于URLRoutingModule,具体实现如下:

     View Code

    public virtual void PostResolveRequestCache(HttpContextBase context)
    {
    RouteData routeData = this.RouteCollection.GetRouteData(context);
    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);
    if (httpHandler == null)
    {
    throw new InvalidOperationException(string.Format(CultureInfo.CurrentUICulture, SR.GetString("UrlRoutingModule_NoHttpHandler"), new object[] { routeHandler.GetType() }));
    }
    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);
    }
    }
    }
    }

    代码中可以很明显看出导航逻辑:通过全局全局路由表Routeable.Routes.GetRouteData()方法获得RouteData,然后通过RouteData.GetHttphandler()获得IRoutehandler,最后通过HttpContext.RemapHandler()注册IRouteHandler.GetHttpHandler()得到的IhttpHandler。代码中的出现的StopRoutingHandler后面再说。

      路由表的切入口在全局静态类RouteTable.Routes,注册的过程放在HttpApplication的Appliation_Start方法中,这个方法如同静态构造函数一般,只启动一次,所以所有需要初始化的全局对象都可以放在这个方法中。vs建立的项目中,Route表的注册被分离出来,放在了App_Start文件夹中,使代码更加清晰。例如以下代码所示,3个路由被注册:

    复制代码
     1 public static void RegisterRoutes(RouteCollection routes) {
     2     routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
     3 
     4     routes.MapRoute(
     5         name: "Default",
     6         url: "{controller}/{action}/{id}",
     7         defaults: new { controller = "Self", action = "Index", id = UrlParameter.Optional }
     8     );
     9 
    10     routes.MapRoute(
    11         name: "CatchAll",
    12         url: "{*input}",
    13         defaults: new { controller = "Home", action = "index" }
    14     );
    15 }
    复制代码

    上面的代码中使用的IgnoreRoute()与MapRoute()皆为扩展方法,用来简化路由注册过程,前者初始化一个Route对象,或者初始化一个IgnoreRouteInternal(继承于Route,私有封闭)对象,然后使用RouteTable.Routes.Add()方法添加如注册表。通过如下代码,可以清楚的看到注册的route:

    复制代码
     1 public void Routes() {
     2     foreach (var routeBase in RouteTable.Routes) {
     3         var route = routeBase as Route;
     4         if (route != null) {
     5             Response.Write(String.Format("{1,26}  {0}<br/>",
     6                 route.GetType().ToString(), route.Url
     7             ).Replace(" ","&nbsp;"));
     8         } else {
     9             Response.Write(String.Format("other:{0}<br/>", routeBase.GetType()));
    10         }
    11     }
    12 }
    复制代码

    得到的结果如下:

    从图中我们可以看到后3个路由正是我们已经注册的3个路由,至于第一个路由,实际上是托管于asp.net的web api应用路由,这个后面再说。同时图中的第二列的Type也佐证了上面所说的不同的Route类说法。

      那么Route类的具体实现呢?首先我们看看Route的继承树:

      

    看着很熟悉,因为集成树中的类在上述的路由图中已经全部出现,整个树的基类是RouteBase,也就是图中高亮的那个,Routes中的集合类型也是RouteBase,下面是RouteBase的定义:

    复制代码
     1 [TypeForwardedFrom("System.Web.Routing, Version=3.5.0.0, Culture=Neutral, PublicKeyToken=31bf3856ad364e35")]
     2 public abstract class RouteBase
     3 {
     4     // Fields
     5     private bool _routeExistingFiles;
     6 
     7     // Methods
     8     protected RouteBase();
     9     public abstract RouteData GetRouteData(HttpContextBase httpContext);
    10     public abstract VirtualPathData GetVirtualPath(RequestContext requestContext, RouteValueDictionary values);
    11 
    12     // Properties
    13     public bool RouteExistingFiles { [TargetedPatchingOptOut("Performance critical to inline this type of method across NGen image boundaries")] get; [TargetedPatchingOptOut("Performance critical to inline this type of method across NGen image boundaries")] set; }
    14 }
    复制代码

    这个一个抽象类,核心方法就是URLRouting中出现过的GetRouteData()方法,还有一个很重要的属性—RouteExistingFiles,这个属性一般用来实现对.aspx兼容支持。RouteBase最常用也是最重要的子类便是Route,代码如下:

    复制代码
     1 [TypeForwardedFrom("System.Web.Routing, Version=3.5.0.0, Culture=Neutral, PublicKeyToken=31bf3856ad364e35")]
     2 public class Route : RouteBase
     3 {
     4     // Fields
     5     private ParsedRoute _parsedRoute;
     6     private string _url;
     7     private const string HttpMethodParameterName = "httpMethod";
     8 
     9     // Methods
    10     public Route(string url, IRouteHandler routeHandler);
    11     public Route(string url, RouteValueDictionary defaults, IRouteHandler routeHandler);
    12     public Route(string url, RouteValueDictionary defaults, RouteValueDictionary constraints, IRouteHandler routeHandler);
    13     public Route(string url, RouteValueDictionary defaults, RouteValueDictionary constraints, RouteValueDictionary dataTokens, IRouteHandler routeHandler);
    14     public override RouteData GetRouteData(HttpContextBase httpContext);
    15     public override VirtualPathData GetVirtualPath(RequestContext requestContext, RouteValueDictionary values);
    16     protected virtual bool ProcessConstraint(HttpContextBase httpContext, object constraint, string parameterName, RouteValueDictionary values, RouteDirection routeDirection);
    17     private bool ProcessConstraints(HttpContextBase httpContext, RouteValueDictionary values, RouteDirection routeDirection);
    18 
    19     // Properties
    20     public RouteValueDictionary Constraints { get; [CompilerGenerated, TargetedPatchingOptOut("Performance critical to inline this type of method across NGen image boundaries")] set; }
    21     public RouteValueDictionary DataTokens { [CompilerGenerated, TargetedPatchingOptOut("Performance critical to inline this type of method across NGen image boundaries")] get; [CompilerGenerated, TargetedPatchingOptOut("Performance critical to inline this type of method across NGen image boundaries")] set; }
    22     public RouteValueDictionary Defaults { [CompilerGenerated, TargetedPatchingOptOut("Performance critical to inline this type of method across NGen image boundaries")] get; [CompilerGenerated, TargetedPatchingOptOut("Performance critical to inline this type of method across NGen image boundaries")] set; }
    23     public IRouteHandler RouteHandler { [CompilerGenerated, TargetedPatchingOptOut("Performance critical to inline this type of method across NGen image boundaries")] get; [CompilerGenerated, TargetedPatchingOptOut("Performance critical to inline this type of method across NGen image boundaries")] set; }
    24     public string Url { get; set; }
    25 }
    复制代码

    相较于RouteBase,Route有5个属性,其中Url,Constraints用来过滤进入请求进行匹配,RouteHandler用来返回IHttpHandler,DataTokens与Defaults则应用于后面的控制器查找,激活与数据传递。这些就以后在细节补充中说这里就不散开了。

      从上面的Route的定义结合最前面说的导航过程,RouteBase->IRouteHandler->IhttpHandler的过程清晰可见。在前面曾经搁置的类StopRoutingHandler就属于IRoutehandler,而这个RouteHandler并不是由Route类获得的,而是前面出现的IgnoreRoute获得的,相关代码:

    1 public IgnoreRouteInternal(string url) : base(url, new StopRoutingHandler())
    2 {
    3 }

    到这里IgnoreRoute()的方法的作用就真正明了了,和MapRoute()方法想反,它定义的不是对某一类路径的拦截,而是放弃对某一类路径的拦截,以便留给后面的管线过程处理,这个管线过程就是后面要说的ExcuteHandler过程(内部,没有公开事件),具体到文中注册的路由可以看到它放弃的是对*.axd类地址的拦截。有趣的是,一般情况下这个.axd不进行放弃路由注册它也一般不会被路由系统捕获,因为我们一般的{controller}/{action}/*的路由样式不可能捕获到带.的路由,除非丧心病狂的使用{*input}等等类型的路由。但是注册的好处是直接跳过,提高效率。

      本来想一次说完的,写到这里发现还有很多没写到,比如全局类型RouteTable等,那就分上下篇吧。最后留个问题:两个路由,一个的Url定义为{input},一个定义为{*input},二者有什么区别?

     
     
     
    标签: asp.net mvcroute
  • 相关阅读:
    解决下载文件过大而不能下载的问题.... 分类: tomcat 20091106 23:24 404人阅读 评论(0) 收藏
    javascript 的参数有长度限制吗?一个细节引起的误区 分类: 网页编程【html、js】 20091110 08:34 1673人阅读 评论(0) 收藏
    cookie的生死之道 分类: 网页编程【html、js】 20091114 03:51 364人阅读 评论(0) 收藏
    java调用存储过程 分类: java 20091112 08:46 479人阅读 评论(1) 收藏
    Boolean.getBoolean(String name)............. 分类: java 20091112 05:42 1093人阅读 评论(1) 收藏
    greatest()函数 和 least()函数 分类: 数据库 20091108 09:21 810人阅读 评论(0) 收藏
    git push u origin master和git push <远程主机名> <本地分支名>:<远程分支名>作用
    Windows下安装Memcached
    关系型数据库性能优化总结
    GridView导出为Excel乱码解决方案
  • 原文地址:https://www.cnblogs.com/Leo_wl/p/3312473.html
Copyright © 2011-2022 走看看