返璞归真,框架商讨

[索引页]
[源码下载]

 

返璞归真 asp.net mvc (2) – 路由(System.Web.Routing)

  ASP.NET Web API 借使选择Web Host格局来过夜,在乞请进入Web API
新闻处理管道从前,就会用ASP.NET
本身的路由系统依据登记的路由表,解析出脚下呼吁的HttpController和Action的称号,以及与指标Action方法有个别参数举行绑定的路由变量。

作者:webabcd

  ASP.NET路由系统包含两地点选拔:

介绍
System.Web.Routing – 此命名空间提供用于 U智跑L
路由的类,通过此类能够利用不映射到大体文件的 U奥迪Q5L

  • 注册路由映射,即注册路由模板和大体文件的相当关系,达成请求U奇骏L地址和拍卖请求的情理地址的分别,可以增进请求U奥迪Q7L可读性,SEO优化,灵活性,即请求UENVISIONL和拍卖请求的大体文件的变迁互不影响
  • UTiggoL生成,依照登记的路由规则变化对应U瑞鹰L,使用这种UGL450L,刚好利用了路由注册的油滑,能够使原本生成的UCRUISERL不间歇,只须要修改路由安插的处理公事。
  • IRouteHandler –
    路由处理程序接口,自定义的路由处理程序都要落到实处那些接口
  • RequestContext – 封装所请求的路由的相干新闻和当前的 http 上下文消息
  • RouteData – 所请求的路由的连锁新闻
  • RouteCollection – 路由集合
  • RouteValueDictionary – 不区分轻重缓急写的 key/value 字典表
  • Route – 路由的相关音信

① 、涉及的类及源码分析

示例
1、MyHandler.cs

  涉及的基本点品种都在System.Web.Routing中,类及首要成员和相互关系如下图:

葡京娱乐注册 1using System;
葡京娱乐注册 2using System.Collections.Generic;
葡京娱乐注册 3using System.Linq;
葡京娱乐注册 4using System.Web;
葡京娱乐注册 5
葡京娱乐注册 6using System.Web.Routing;
葡京娱乐注册 7
葡京娱乐注册 8namespace MVC.RoutingDemo
葡京娱乐注册 9葡京娱乐注册 10葡京娱乐注册 11{
葡京娱乐注册 12葡京娱乐注册 13    /**//// <summary>
葡京娱乐注册 14    /// 路由处理程序
葡京娱乐注册 15    /// </summary>
葡京娱乐注册 16    public class MyRouteHandler : IRouteHandler
葡京娱乐注册 17葡京娱乐注册 18    葡京娱乐注册 19{
葡京娱乐注册 20葡京娱乐注册 21        /**//*
葡京娱乐注册 22         * IRouteHandler – 路由处理程序接口,自定义的路由处理程序都要完毕那些接口 
葡京娱乐注册 23         *     该接口有1个艺术 IHttpHandler GetHttpHandler(RequestContext requestContext)
葡京娱乐注册 24         *     此方法必要回到一个甩卖该路由的 http 处理程序 (HttpHandler)
葡京娱乐注册 25         * RequestContext – 封装所请求的路由的连锁新闻和方今的 http 上下文音信
葡京娱乐注册 26         *     RequestContext.HttpContext – 当前的 http 上下文音信
葡京娱乐注册 27         *     RequestContext.RouteData – 所请求的路由的相关新闻
葡京娱乐注册 28         */
葡京娱乐注册 29
葡京娱乐注册 30        public IHttpHandler GetHttpHandler(RequestContext requestContext)
葡京娱乐注册 31葡京娱乐注册 32        葡京娱乐注册 33{
葡京娱乐注册 34            return new MyHttpHandler(requestContext);
葡京娱乐注册 35        }
葡京娱乐注册 36    }
葡京娱乐注册 37
葡京娱乐注册 38葡京娱乐注册 39    /**//// <summary>
葡京娱乐注册 40    /// 自定义的 http 处理程序,由路由控制利用哪个 http 处理程序
葡京娱乐注册 41    /// </summary>
葡京娱乐注册 42    public class MyHttpHandler : IHttpHandler
葡京娱乐注册 43葡京娱乐注册 44    葡京娱乐注册 45{
葡京娱乐注册 46葡京娱乐注册 47        public RequestContext RequestContext 葡京娱乐注册 48{ get; private set; }
葡京娱乐注册 49        
葡京娱乐注册 50        public MyHttpHandler(RequestContext context)
葡京娱乐注册 51葡京娱乐注册 52        葡京娱乐注册 53{
葡京娱乐注册 54            RequestContext = context;
葡京娱乐注册 55        }
葡京娱乐注册 56
葡京娱乐注册 57        public void ProcessRequest(HttpContext httpContext)
葡京娱乐注册 58葡京娱乐注册 59        葡京娱乐注册 60{
葡京娱乐注册 61葡京娱乐注册 62            /**//*
葡京娱乐注册 63             * RouteData – 所请求的路由的相关音信
葡京娱乐注册 64             *     RouteData.Values – 1个字典表(key – 路由参数;value – 路由值)
葡京娱乐注册 65             *     RouteData.DataTokens – 自定义需求传递的数目,也是2个字典表
葡京娱乐注册 66             *     RouteData.GetRequiredString(string key) – 获取钦赐的路由参数所对应的路由值
葡京娱乐注册 67             */
葡京娱乐注册 68
葡京娱乐注册 69            httpContext.Response.Write(“相关参数为:<br />”);
葡京娱乐注册 70            foreach (var dic in RequestContext.RouteData.Values)
葡京娱乐注册 71葡京娱乐注册 72            葡京娱乐注册 73{
葡京娱乐注册 74                httpContext.Response.Write(dic.Key + ” : ” + dic.Value + “<br />”);
葡京娱乐注册 75            }
葡京娱乐注册 76
葡京娱乐注册 77            httpContext.Response.Write(“相关Token为:<br />”);
葡京娱乐注册 78            foreach (var dic in RequestContext.RouteData.DataTokens)
葡京娱乐注册 79葡京娱乐注册 80            葡京娱乐注册 81{
葡京娱乐注册 82                httpContext.Response.Write(dic.Key + ” : ” + dic.Value + “<br />”);
葡京娱乐注册 83            }
葡京娱乐注册 84        }
葡京娱乐注册 85
葡京娱乐注册 86        public bool IsReusable
葡京娱乐注册 87葡京娱乐注册 88        葡京娱乐注册 89{
葡京娱乐注册 90葡京娱乐注册 91            get 葡京娱乐注册 92{ return false; }
葡京娱乐注册 93        }
葡京娱乐注册 94    }
葡京娱乐注册 95
葡京娱乐注册 96葡京娱乐注册 97    /**//// <summary>
葡京娱乐注册 98    /// 借使有 n 多的路由处理程序,为了方便调用,收缩代码,大家能够将其写成一个 Factory 类,如下:
葡京娱乐注册 99    /// </summary>
葡京娱乐注册 100    public class RouteHandlerFactory : IRouteHandler
葡京娱乐注册 101葡京娱乐注册 102    葡京娱乐注册 103{
葡京娱乐注册 104        private string _name;
葡京娱乐注册 105        public RouteHandlerFactory(string name)
葡京娱乐注册 106葡京娱乐注册 107        葡京娱乐注册 108{
葡京娱乐注册 109            _name = name;
葡京娱乐注册 110        }
葡京娱乐注册 111
葡京娱乐注册 112        public IHttpHandler GetHttpHandler(RequestContext requestContext)
葡京娱乐注册 113葡京娱乐注册 114        葡京娱乐注册 115{
葡京娱乐注册 116            if (_name == “My”)
葡京娱乐注册 117                return new MyHttpHandler(requestContext);
葡京娱乐注册 118
葡京娱乐注册 119            return new MyHttpHandler(requestContext);
葡京娱乐注册 120        }
葡京娱乐注册 121    }
葡京娱乐注册 122
葡京娱乐注册 123葡京娱乐注册 124    /**//// <summary>
葡京娱乐注册 125    /// 演示不通过路由,依据 web.config 中的 HttpHandler 相关铺排,因而 HttpHandler 直接处理有关请球。具体配置见 Global.asax
葡京娱乐注册 126    /// </summary>
葡京娱乐注册 127    public class XXXHttpHandler : IHttpHandler
葡京娱乐注册 128葡京娱乐注册 129    葡京娱乐注册 130{
葡京娱乐注册 131        public XXXHttpHandler()
葡京娱乐注册 132葡京娱乐注册 133        葡京娱乐注册 134{
葡京娱乐注册 135
葡京娱乐注册 136        }
葡京娱乐注册 137
葡京娱乐注册 138        public void ProcessRequest(HttpContext context)
葡京娱乐注册 139葡京娱乐注册 140        葡京娱乐注册 141{
葡京娱乐注册 142            context.Response.Write(context.Request.Url.ToString());
葡京娱乐注册 143        }
葡京娱乐注册 144
葡京娱乐注册 145        public bool IsReusable
葡京娱乐注册 146葡京娱乐注册 147        葡京娱乐注册 148{
葡京娱乐注册 149葡京娱乐注册 150            get 葡京娱乐注册 151{ return false; }
葡京娱乐注册 152        }
葡京娱乐注册 153    }
葡京娱乐注册 154}

   葡京娱乐注册 155

2、Web.config

1、RouteBase

葡京娱乐注册 156<?xml version=”1.0″?>
葡京娱乐注册 157<configuration>
葡京娱乐注册 158  <system.web>
葡京娱乐注册 159    <httpHandlers>
葡京娱乐注册 160
葡京娱乐注册 161      <!–
葡京娱乐注册 162      配置贰个自定义的 HttpHandler,用于拍卖后缀名为 xxx 的页面
葡京娱乐注册 163      假使不必要将 *.xxx 交给路由处理,而是从来让内定的 HttpHandler 处理,请参考 Global.asax 中的配置
葡京娱乐注册 164      –>
葡京娱乐注册 165      <add verb=”*” path=”*.xxx” type=”MVC.RoutingDemo.XXXHttpHandler” />
葡京娱乐注册 166
葡京娱乐注册 167    </httpHandlers>
葡京娱乐注册 168    <httpModules>
葡京娱乐注册 169      
葡京娱乐注册 170      <!–
葡京娱乐注册 171      UrlRoutingModule – 用于匹配 asp.net 应用程序中的路由的 http 请求
葡京娱乐注册 172          该模块找到匹配路由后,会招来 IRouteHandler 对象,以搜寻该路由,然后从该路由处理程序获取贰个 IHttpHandler 对象,并将该对象用作当前乞请的 http 处理程序
葡京娱乐注册 173      –>
葡京娱乐注册 174      <add name=”UrlRoutingModule” type=”System.Web.Routing.UrlRoutingModule, System.Web.Routing, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35″/>
葡京娱乐注册 175      
葡京娱乐注册 176    </httpModules>
葡京娱乐注册 177  </system.web>
葡京娱乐注册 178</configuration>
葡京娱乐注册 179

  public abstract class RouteBase
  {
    private bool _routeExistingFiles = true;
    //依据路由模板与请求的U大切诺基L实行匹配,假设成功再次回到RouteData,不然重临NULL
    public abstract RouteData GetRouteData(HttpContextBase httpContext);
    //采取钦定的路由变量列表(包蕴名称和值)与URubiconL路由模板举行匹配,若匹配成功,再次回到完整U福睿斯L,不然重回NULL
    public abstract VirtualPathData GetVirtualPath(RequestContext requestContext, RouteValueDictionary values);
    //表示是不是对现有的情理文件实行路由,暗中同意值为true,即因而地点“/employees/hr/index.aspx”
是造访不到 Index.aspx页面

3、Global.asax.cs

    //不过有时我们希望以物理文件路径方法来走访对应的物理文件,能够设置该值为false,就可以访问到Index.aspx页面
    public bool RouteExistingFiles
    {
      get
      {
        return this._routeExistingFiles;
      }
      set
      {
        this._routeExistingFiles = value;
      }
    }
  }

葡京娱乐注册 180using System;
葡京娱乐注册 181using System.Collections.Generic;
葡京娱乐注册 182using System.Linq;
葡京娱乐注册 183using System.Web;
葡京娱乐注册 184using System.Web.Mvc;
葡京娱乐注册 185using System.Web.Routing;
葡京娱乐注册 186
葡京娱乐注册 187namespace MVC
葡京娱乐注册 188葡京娱乐注册 189葡京娱乐注册 190{
葡京娱乐注册 191    // Note: For instructions on enabling IIS6 or IIS7 classic mode, 
葡京娱乐注册 192    // visit http://go.microsoft.com/?LinkId=9394801
葡京娱乐注册 193
葡京娱乐注册 194    public class MvcApplication : System.Web.HttpApplication
葡京娱乐注册 195葡京娱乐注册 196    葡京娱乐注册 197{
葡京娱乐注册 198        public static void RegisterRoutes(RouteCollection routes)
葡京娱乐注册 199葡京娱乐注册 200        葡京娱乐注册 201{
葡京娱乐注册 202葡京娱乐注册 203            /**//* 路由方向:自上而下,查找到分外的就去处理,而不会持续往下做匹配 */
葡京娱乐注册 204
葡京娱乐注册 205葡京娱乐注册 206            /**//*
葡京娱乐注册 207             * RouteCollection – 路由集合
葡京娱乐注册 208             *     RouteCollection.IgnoreRoute() – 钦赐的地点不由路由拍卖
葡京娱乐注册 209             *     RouteCollection.Add() – 新增贰个路由配置
葡京娱乐注册 210             *     RouteCollection.MapRoute() – 映射一个路由(Add() 方法的简化版,内部会自行调用 MvcRouteHandler)
葡京娱乐注册 211             */
葡京娱乐注册 212
葡京娱乐注册 213            // .asd 文件不走此路由
葡京娱乐注册 214            routes.IgnoreRoute(“{resource}.axd/{*pathInfo}”);
葡京娱乐注册 215            // .xxx 文件不走此路由
葡京娱乐注册 216            routes.Add(new Route(“{resource}.xxx/{*pathInfo}”, new StopRoutingHandler()));
葡京娱乐注册 217
葡京娱乐注册 218
葡京娱乐注册 219葡京娱乐注册 220            /**葡京娱乐注册,//*
葡京娱乐注册 221             * RouteValueDictionary – 不区分轻重缓急写的 key/value 字典表
葡京娱乐注册 222             * Route – 路由的连锁音信
葡京娱乐注册 223             *     Route.Url – 路由的 url 匹配形式,{ } 内的为必要般配的路由参数名
葡京娱乐注册 224             *     Route.Defaults – 路由参数的暗许值
葡京娱乐注册 225             *     Route.RouteHandler – 路由相应的路由处理程序
葡京娱乐注册 226             *     Route.DataTokens – 自定义须要传递的多少
葡京娱乐注册 227             *     Route.Constraints – 约束参数值的实用(能够是正则表明式(不区分轻重缓急写),也足以是促成了 IRouteConstraint 的对象)
葡京娱乐注册 228             */
葡京娱乐注册 229
葡京娱乐注册 230            Route route = new Route(
葡京娱乐注册 231                “Routing/{parent}/{child}”,
葡京娱乐注册 232
葡京娱乐注册 233                // RouteValueDictionary – 能够吸纳1个匿名对象为参数,属性名转换为 key, 属性值转换为 value
葡京娱乐注册 234葡京娱乐注册 235                new RouteValueDictionary(new 葡京娱乐注册 236{ parent = “ria”, child = “silverlight”, controller = “Product”, action = “Index” }),
葡京娱乐注册 237
葡京娱乐注册 238                new RoutingDemo.MyRouteHandler()
葡京娱乐注册 239            );
葡京娱乐注册 240葡京娱乐注册 241            route.DataTokens = new RouteValueDictionary(new 葡京娱乐注册 242{ token1 = “abc”, token2 = “xyz” });
葡京娱乐注册 243
葡京娱乐注册 244            // HttpMethodConstraint – 完结了 IRouteConstraint 接口的类,用于约束 http 方法
葡京娱乐注册 245葡京娱乐注册 246            route.Constraints = new RouteValueDictionary(new 葡京娱乐注册 247{ parent = @”^[a-zA-Z]+$”, httpMethod = new HttpMethodConstraint(“GET”) });
葡京娱乐注册 248
葡京娱乐注册 249            // 将路由添加进路由集合,名称能够不管设置,但不能够不唯一(也得以不设置路由名称)
葡京娱乐注册 250            routes.Add(“MyRoutingDemo”, route);
葡京娱乐注册 251            // routes.Add(route);
葡京娱乐注册 252
葡京娱乐注册 253
葡京娱乐注册 254            // * – 路由也援助通配符
葡京娱乐注册 255            // {*param} – 代表匹配任意值,在那之中路由参数名为 param
葡京娱乐注册 256葡京娱乐注册 257            routes.Add(new Route(“Wildcard/{*param}”, new RouteValueDictionary(new 葡京娱乐注册 258{ controller = “Product”, action = “Index” }), new RoutingDemo.MyRouteHandler()));
葡京娱乐注册 259
葡京娱乐注册 260
葡京娱乐注册 261            // MapRoute() 封装了 Add(), MapRoute() 内部会自行调用 MvcRouteHandler
葡京娱乐注册 262            // 个中必供给有 controller 项和 action 项
葡京娱乐注册 263            // 个中设置 namespaces 参数也正是 route.DataTokens[“Namespaces”] = namespaces;
葡京娱乐注册 264            routes.MapRoute(
葡京娱乐注册 265                “Products”,
葡京娱乐注册 266                “ProductList/{pageIndex}”,
葡京娱乐注册 267葡京娱乐注册 268                new 葡京娱乐注册 269{ controller = “Product”, action = “Index”, pageIndex = 0 }
葡京娱乐注册 270            );
葡京娱乐注册 271
葡京娱乐注册 272            routes.MapRoute(
葡京娱乐注册 273                “Default”,                                              // Route name
葡京娱乐注册 274                “{controller}/{action}/{id}”,                           // URL with parameters
葡京娱乐注册 275葡京娱乐注册 276                new 葡京娱乐注册 277{ controller = “Home”, action = “Index”, id = “” }  // Parameter defaults
葡京娱乐注册 278            );
葡京娱乐注册 279        }
葡京娱乐注册 280
葡京娱乐注册 281        protected void Application_Start()
葡京娱乐注册 282葡京娱乐注册 283        葡京娱乐注册 284{
葡京娱乐注册 285            RegisterRoutes(RouteTable.Routes);
葡京娱乐注册 286
葡京娱乐注册 287            // 调节和测试路由(要求 RouteDebug.dll),调用如下语句后,会在各种页面都彰显详细的路由音信
葡京娱乐注册 288            // RouteDebug.RouteDebugger.RewriteRoutesForTesting(RouteTable.Routes);
葡京娱乐注册 289        }
葡京娱乐注册 290    }
葡京娱乐注册 291}
葡京娱乐注册 292
葡京娱乐注册 293
葡京娱乐注册 294// 部署在 iis 应注意
葡京娱乐注册 295// 配置通配符映射程序,类似如下地址
葡京娱乐注册 296// C:\WINDOWS\Microsoft.NET\Framework\v2.0.50727\aspnet_isapi.dll   
葡京娱乐注册 297// 不要勾选“确认文件是不是存在”

2、Route

OK
[源码下载]

  RouteBase唯一子类,基于路由模板格局的路由匹配规则就定义在里面,向全局路由表中添加的正是三个Route对象。

  public class Route
: RouteBase
  {
    private const string HttpMethodParameterName =
“httpMethod”;
    private string _url;
    private ParsedRoute _parsedRoute;

    //构造函数,前边省略N个重载
    public Route(string url, RouteValueDictionary defaults, RouteValueDictionary constraints, RouteValueDictionary dataTokens, IRouteHandler routeHandler)
    {
      this.Url = url;
      this.Defaults =
defaults;
      this.Constraints =
constraints;
      this.DataTokens =
dataTokens;
      this.RouteHandler =
routeHandler;
    }

    //为路由模板中的变量以正则表明式的形武设定一些封锁原则,Key为变量名,Value为正则表明式

    //假如有定义,匹配也要满足该约束
    public RouteValueDictionary Constraints { get; set; }
    //存款和储蓄额外的变量值
    public RouteValueDictionary DataTokens { get; set; }
    //路由变量暗中认可值,也不自然要定义在路由模板中
    public RouteValueDictionary Defaults { get; set; }

    public IRouteHandler RouteHandler { get; set; }

    //路由模板,如/weather/{areacode}/{days},请求的ULacrosseL正是跟该模板实行匹配,/分割成多个段,每一种段又分变量(areacode,days)和字面量(weather)

    //匹配的七个尺码,段数和路由模板相同,以及对应文本段内容也要一如既往,注,UMuranoL大小写不灵敏
    public string Url
    {
      get
      {
        return this._url ?? string.Empty;
      }
      set
      {
        this._parsedRoute =
RouteParser.Parse(value);
        this._url = value;
      }
    }

    //依据路由模板与请求的U奥迪Q5L进行匹配,尽管成功再次回到RouteData,否则再次回到NULL

    public override RouteData GetRouteData(HttpContextBase httpContext)
    {
      RouteValueDictionary
values = this._parsedRoute.Match(httpContext.Request.AppRelativeCurrentExecutionFilePath.Substring(2)

  • httpContext.Request.PathInfo,         this.Defaults);
          if (values == null)
            return (RouteData)null;
          RouteData routeData =
    new RouteData((RouteBase)this, this.RouteHandler);
          if
    (!this.ProcessConstraints(httpContext, values, RouteDirection.IncomingRequest))
            return (RouteData)null;
          foreach (KeyValuePair<string, object> keyValuePair in values)
            routeData.Values.Add(keyValuePair.Key,
    keyValuePair.Value);
          if (this.DataTokens != null)
          {
            foreach (KeyValuePair<string, object> dataToken in this.DataTokens)
            routeData.DataTokens[dataToken.Key] =
    dataToken.Value;
          }
          return routeData;
        }

    //接纳钦定的路由变量列表(蕴涵名称和值)与UTiguanL路由模板进行匹配,若匹配成功,重回完整UHavalL,不然重回NULL
    public override VirtualPathData GetVirtualPath(RequestContext requestContext, RouteValueDictionary values)
    {
      BoundUrl boundUrl =
this._parsedRoute.Bind(requestContext.RouteData.Values,
values, this.Defaults, this.Constraints);
      if (boundUrl == null)
        return (VirtualPathData)null;
      if (!this.ProcessConstraints(requestContext.HttpContext,
boundUrl.Values, RouteDirection.UrlGeneration))
        return (VirtualPathData)null;
      VirtualPathData
virtualPathData = new VirtualPathData((RouteBase)this, boundUrl.Url);
      if (this.DataTokens != null)
      {
        foreach (KeyValuePair<string, object> dataToken in this.DataTokens)
          virtualPathData.DataTokens[dataToken.Key] =
dataToken.Value;
      }
      return
virtualPathData;
    }

    //处理约束
    protected virtual bool ProcessConstraint(HttpContextBase httpContext, object constraint, string parameterName, RouteValueDictionary values, RouteDirection
      routeDirection)
    {
      IRouteConstraint
routeConstraint = constraint as
IRouteConstraint;
      if (routeConstraint !=
null)
        return
routeConstraint.Match(httpContext, this, parameterName, values,
routeDirection);
      string str = constraint
as string;
      if (str == null)
        throw new InvalidOperationException(string.Format((IFormatProvider)CultureInfo.CurrentUICulture,
                            System.Web.SR.GetString(“Route_ValidationMustBeStringOrCustomConstraint”),
new object[2]
      {
        (object)
parameterName,
        (object) this.Url
      }));
      object obj;
      values.TryGetValue(parameterName, out obj);
      return Regex.IsMatch(Convert.ToString(obj, (IFormatProvider)CultureInfo.InvariantCulture), “^(” + str + “)$”, RegexOptions.IgnoreCase |
              RegexOptions.CultureInvariant);
    }

    private bool ProcessConstraints(HttpContextBase httpContext, RouteValueDictionary values, RouteDirection routeDirection)
    {
      if (this.Constraints != null)
      {
        foreach (KeyValuePair<string, object> constraint in this.Constraints)
        {
          if (!this.ProcessConstraint(httpContext,
constraint.Value, constraint.Key, values, routeDirection))
          return false;
        }
      }
      return true;
    }

  }

  其它,RequestContext是对Http请求上下文和路由数据的包装

  public class RequestContext
  {
    public RequestContext()
    {
    }

    public RequestContext(HttpContextBase httpContext, RouteData routeData)
    {
      if (httpContext ==
null)
        throw new ArgumentNullException(nameof(httpContext));
      if (routeData == null)
        throw new ArgumentNullException(nameof(routeData));
      this.HttpContext =
httpContext;
      this.RouteData =
routeData;
    }
    //请求上下文
    public virtual HttpContextBase HttpContext { get; set; }
    //路由数量
    public virtual RouteData RouteData { get; set; }
  }

3、RouteData

   RouteBase的GetRouteData方法的回到类型,用于封装解析后路由数据,其用RouteValueDictionary保存路由变量数据,RouteValueDictionary是—个字典,其
Key和 Value分别代表路由变量的称谓和值,定义如下:

  public class RouteValueDictionary : IDictionary<string, object>

  {

  }

  public class RouteData
  {
    private RouteValueDictionary _values = new RouteValueDictionary();
    private RouteValueDictionary _dataTokens = new RouteValueDictionary();
    private IRouteHandler _routeHandler;

    public RouteData()
    {
    }

    public RouteData(RouteBase route, IRouteHandler routeHandler)
    {
      this.Route = route;
      this.RouteHandler =
routeHandler;
    }

    //是一向附加到Route上的自定义变量。
    public RouteValueDictionary DataTokens
    {
      get
      {
        return this._dataTokens;
      }
    }

    //解析它的 Route对象

    public RouteBase Route { get; set; }

    //提供最 终用
于处理请求的HttpHandIer对象(通过调用其GetHttpHandler方法获取)

    //能够在构造函数中传播,也能够属性赋值
    public IRouteHandler RouteHandler
    {
      get
      {
        return this._routeHandler;
      }
      set
      {
        this._routeHandler
= value;
      }
    }

    //当中的路由变量是Route通过对请求ULX570L的解析得到的
    public RouteValueDictionary Values
    {
      get
      {
        return this._values;
      }
    }

    //获取包蕴某个固定名称的变量值(如controller和action)对应的值
    public string GetRequiredString(string valueName)
    {
      object obj;
      if (this.Values.TryGetValue(valueName, out obj))
      {
        string str = obj as string;
        if (!string.IsNullOrEmpty(str))
          return str;
      }
      //不存在直接抛出尤其
      throw new InvalidOperationException(string.Format((IFormatProvider)CultureInfo.CurrentUICulture,
System.Web.SR.GetString(“RouteData_RequiredValue”), new         object[1]
          {
            (object)
valueName
          }));
    }
  }

  

  public interface IRouteHandler
  {
    IHttpHandler
GetHttpHandler(RequestContext
requestContext);
  }

4、VirtualPathData

  RouteBase的GeVirtualPathData方法的归来类型

  public class VirtualPathData
  {
    private RouteValueDictionary _dataTokens = new RouteValueDictionary();
    private string
_virtualPath;

    public VirtualPathData(RouteBase route, string virtualPath)
    {
      this.Route = route;
      this.VirtualPath =
virtualPath;
    }

    //来源于附加到 Route的
自定义变量集合
    public RouteValueDictionary DataTokens
    {
      get
      {
        return this._dataTokens;
      }
    }
    //当时分析的路由对象
    public RouteBase Route { get; set; }

    //完整虚拟路径
    public string VirtualPath
    {
      get
      {
        return
this._virtualPath ?? string.Empty;
      }
      set
      {
        this._virtualPath =
value;
      }
    }
  }

5、RouteTable
Routes RouteCollection

  全局路由表,即RouteTable类的静态属性Routes
类型为RouteCollection,通过中间的MapPageRoute方法开始展览路由映射

  public class RouteTable
  {
    private static RouteCollection _instance = new RouteCollection();

    public static RouteCollection Routes
    {
      get
      {
        return
RouteTable._instance;
      }
    }
  }

  RouteCollection 是Route的集合

  首要逻辑:

    RouteCollection的GetRouteData和GetVirtalPath方法会遍历集合中的种种Route对象,并传播给定的参数调用同名方法直到找到二个匹配的Route(重回值不为Null),并回到相应的RouteData和VirtaulPathData对象,假设集合中其他1个Route都不合作,末了回到NULL

  读写锁的利用:

    RouteCollection这一个集合对象不是线程安全的,使用ReaderWriterLockSlim举行线程读写同步,八个线程能够同时读,其余情状都不容许,二个线程写时,其余的线程不可能读或写,3个线程在读时候,其他线程只好读,不能够写,即七个线程只可以读读,不可能读写、写写;

    在对聚集进行读取或更新时候,会调用GetReadLock和GetWriteLock方法取得读锁或写锁,重回的是内嵌私有类型:ReadLockDispsoabled和WriteLockDispsoabled,他们落到实处了接口IDispsoabled,是对里德rWriterLockSlim的读写锁效率的卷入。

  public class RouteCollection : Collection<RouteBase>
  {
    private Dictionary<string, RouteBase> _namedMap = new Dictionary<string, RouteBase>((IEqualityComparer<string>)StringComparer.OrdinalIgnoreCase);
    private ReaderWriterLockSlim _rwLock = new ReaderWriterLockSlim();

    public RouteCollection()
    {
    }

    public bool
RouteExistingFiles { get; set; }

    public void Add(string name, RouteBase item)
    {
      //…
      this.Add(item);
      if (!string.IsNullOrEmpty(name))
        this._namedMap[name] = item;
      Route route = item as
Route;
      if (route == null || route.RouteHandler == null)
        return;
    }

    //省略N个重载方法
    public Route MapPageRoute(string routeName, string routeUrl, string physicalFile, bool checkPhysicalUrlAccess, RouteValueDictionary defaults, RouteValueDictionary
      constraints, RouteValueDictionary dataTokens)
    {
      if (routeUrl == null)
        throw new ArgumentNullException(nameof(routeUrl));
      //新建路由对象,IRouteHandler直接new PageRouteHandler
      Route route = new Route(routeUrl, defaults, constraints,
dataTokens, (IRouteHandler)new PageRouteHandler(physicalFile,
checkPhysicalUrlAccess));
      //添加进去
      this.Add(routeName,
(RouteBase)route);
      return route;
    }

    protected override void
ClearItems()
    {
      this._namedMap.Clear();
      base.ClearItems();
    }

    public IDisposable GetReadLock()
    {
      this._rwLock.EnterReadLock();
      return (IDisposable)new System.Web.Routing.RouteCollection.ReadLockDisposable(this._rwLock);
    }

    private RequestContext GetRequestContext(RequestContext requestContext)
    {
      if (requestContext !=
null)
        return
requestContext;
      HttpContext current =
HttpContext.Current;
      if (current == null)
        throw new InvalidOperationException(System.Web.SR.GetString(“RouteCollection_RequiresContext”));
      return new RequestContext((HttpContextBase)new HttpContextWrapper(current), new RouteData());
    }

    private bool
IsRouteToExistingFile(HttpContextBase httpContext)
    {
      string executionFilePath
= httpContext.Request.AppRelativeCurrentExecutionFilePath;
      if (!(executionFilePath
!= “~/”) || this.VPP == null)
        return false;
      if (!this.VPP.FileExists(executionFilePath))
        return
this.VPP.DirectoryExists(executionFilePath);
      return true;
    }

    public RouteData GetRouteData(HttpContextBase httpContext)
    {
      …
      using (this.GetReadLock())
      {
        //遍历集合中具有RouteBase,并调用其GetRouteData方法,找到了就随即赶回
        foreach (RouteBase routeBase in (Collection<RouteBase>)this)
        {
          RouteData
routeData = routeBase.GetRouteData(httpContext);
          if (routeData !=
null)
          {
            if
(!routeBase.RouteExistingFiles)
            {
              if
(!flag2)
                flag1 = this.IsRouteToExistingFile(httpContext);
              if
(flag1)
                return (RouteData)null;
            }
            return
routeData;
          }
        }
      }
      return (RouteData)null;
    }

    public VirtualPathData GetVirtualPath(RequestContext requestContext, RouteValueDictionary values)
    {
      requestContext = this.GetRequestContext(requestContext);
      using (this.GetReadLock())
      {
        //遍历集合中有所RouteBase,并调用其GetVirtualPath方法,找到了就立马重回
        foreach (RouteBase routeBase in (Collection<RouteBase>)this)
        {
          VirtualPathData
virtualPath = routeBase.GetVirtualPath(requestContext, values);
          if (virtualPath
!= null)
          {
            virtualPath.VirtualPath =
this.NormalizeVirtualPath(requestContext, virtualPath.VirtualPath);
            return
virtualPath;
          }
        }
      }
      return (VirtualPathData)null;
    }

    public VirtualPathData GetVirtualPath(RequestContext requestContext, string name, RouteValueDictionary values)
    {
      requestContext = this.GetRequestContext(requestContext);
      if (string.IsNullOrEmpty(name))
        return this.GetVirtualPath(requestContext,
values);
      RouteBase routeBase;
      bool flag;
      using (this.GetReadLock())
        flag = this._namedMap.TryGetValue(name, out routeBase);
      if (flag)
      {
        VirtualPathData
virtualPath = routeBase.GetVirtualPath(requestContext, values);
        if (virtualPath ==
null)
          return (VirtualPathData)null;
        virtualPath.VirtualPath =
this.NormalizeVirtualPath(requestContext, virtualPath.VirtualPath);
        return
virtualPath;
      }
      throw new ArgumentException(string.Format((IFormatProvider)CultureInfo.CurrentUICulture,
System.Web.SR.GetString(“RouteCollection_NameNotFound”), new         object[1]
        {
          (object) name
        }), nameof(name));
     }

    public IDisposable GetWriteLock()
    {
      this._rwLock.EnterWriteLock();
      return (IDisposable)new System.Web.Routing.RouteCollection.WriteLockDisposable(this._rwLock);
    }

    //忽略路由
    public void Ignore(string url)
    {
      this.Ignore(url, (object)null);
    }

    public void Ignore(string url, object constraints)
    {
      if (url == null)
        throw new ArgumentNullException(nameof(url));
      System.Web.Routing.RouteCollection.IgnoreRouteInternal ignoreRouteInternal =
new System.Web.Routing.RouteCollection.IgnoreRouteInternal(url);
      RouteValueDictionary
routeValueDictionary = new RouteValueDictionary(constraints);
      ignoreRouteInternal.Constraints = routeValueDictionary;
      this.Add((RouteBase)ignoreRouteInternal);
    }

    protected override void
InsertItem(int index, RouteBase item)
    {
      if (item == null)
        throw new ArgumentNullException(nameof(item));
      if (this.Contains(item))
        throw new ArgumentException(string.Format((IFormatProvider)CultureInfo.CurrentCulture,
System.Web.SR.GetString(“RouteCollection_DuplicateEntry”), new           object[0]),
nameof(item));
      base.InsertItem(index,
item);
    }

    protected override void
RemoveItem(int index)
    {
      this.RemoveRouteName(index);
      base.RemoveItem(index);
    }

    private void
RemoveRouteName(int index)
    {
      RouteBase routeBase =
this[index];
      foreach (KeyValuePair<string, RouteBase> named in this._namedMap)
      {
        if (named.Value ==
routeBase)
        {
          this._namedMap.Remove(named.Key);
          break;
        }
      }
    }

    protected override void
SetItem(int index, RouteBase item)
    {
      if (item == null)
        throw new ArgumentNullException(nameof(item));
      if (this.Contains(item))
        throw new ArgumentException(string.Format((IFormatProvider)CultureInfo.CurrentCulture,
System.Web.SR.GetString(“RouteCollection_DuplicateEntry”), new           object[0]),
nameof(item));
      this.RemoveRouteName(index);
      base.SetItem(index,
item);
    }

    private class ReadLockDisposable : IDisposable
    {
      private ReaderWriterLockSlim _rwLock;

      public
ReadLockDisposable(ReaderWriterLockSlim rwLock)
      {
        this._rwLock =
rwLock;
      }

      void IDisposable.Dispose()
      {
        this._rwLock.ExitReadLock();
      }
    }

    private class WriteLockDisposable : IDisposable
    {
      private ReaderWriterLockSlim _rwLock;

      public
WriteLockDisposable(ReaderWriterLockSlim rwLock)
      {
        this._rwLock =
rwLock;
      }

      void IDisposable.Dispose()
      {
        this._rwLock.ExitWriteLock();
      }
    }

    private sealed class IgnoreRouteInternal : Route
    {
      public
IgnoreRouteInternal(string url)
        : base(url, (IRouteHandler)new StopRoutingHandler())
      {
      }

      public override VirtualPathData GetVirtualPath(RequestContext requestContext, RouteValueDictionary routeValues)
      {
        return (VirtualPathData)null;
      }
    }
  } 

6、IRouteConstraint

  除了用正则表明式对某些变量实行约束外,还足以用1个兑现了IRouteConstraint接口的对象对一切请求进行约束

  public interface IRouteConstraint
  {
    bool Match(HttpContextBase httpContext, Route route, string parameterName, RouteValueDictionary values, RouteDirection routeDirection);
  }

二 、注册路由映射

一 、基本使用MapPageRoute方法

  注册路由映射核心是在全局路由表RouteTable.Routes里添加叁个Route对象,通过调用路由表的MapPageRoute方法,该方法能够传递各个有关参数,如前一节的源码

  public Route MapPageRoute(string routeName, string routeUrl, string physicalFile, bool checkPhysicalUrlAccess, RouteValueDictionary defaults, RouteValueDictionary
      constraints, RouteValueDictionary dataTokens)

  能够内定路由名称routeName,模板routeUrl,对应处理的情理文件physicalFile,是还是不是核查路由指标地方的UCR-VL授权,暗许值defaults,约束constraints,附加到
Route的 自定义变量集合dataTokens

  如大家能够按上面传递参数:   

    var defaults = new RouteValueDictionary { { “areacode”, “010” }, { “days”, 2 }};

    //约束,正则表明式
    var constaints = new RouteValueDictionary { { “areacode”, @”0\d{2,3}” }, { “days”, @”[1-3]” } };

    //对变量默许值的注解
    var dataTokens = new RouteValueDictionary { { “defaultCity”, “BeiJing” }, { “defaultDays”, 2 } };

    RouteTable.Routes.MapPageRoute(“default”, “{areacode}/{days}”,”~/weather.aspx”, false, defaults, constaints, dataTokens);

   由上面源码可见,会确立如下Route对象

    Route route = new Route(routeUrl, defaults, constraints,
dataTokens, (IRouteHandler)new PageRouteHandler(physicalFile,
checkPhysicalUrlAccess));

   IRouteHandler是new PageRouteHandler(physicalFile,
checkPhysicalUrlAccess)

② 、自定义约束IRouteConstraint

  接下去,大家用一连自IRouteConstraint约束类来限制请求允许的法子   

    public class HttpMethodConstraint : IRouteConstraint
    {
      public HttpMethodConstraint(params string[] allowedMethods);

      public ICollection<string> AllowedMethods { get; }

      protected virtual bool Match(HttpContextBase httpContext, Route route, string parameterName, RouteValueDictionary values, RouteDirection routeDirection);
    }

  使用方式:

     { “httpMethod”, new HttpMethodConstraint(“POST”) } 

  当然,可以传三个

三 、直接路由物理文件(RouteExistingFiles)

  RouteCollection和RouteBase都有质量RouteExistingFiles ,私下认可值分别为
false和true,要学有所成匹配路由,要知足五个规格

  两者RouteExistingFiles 都为true,Route
的U汉兰达L模板和请求UPAJEROL匹配,不然不会得到RouteData数据。

  如我们按守旧方法访问二个物理文件http://myhost:1111/my.aspx,路由配置一样

  RouteTable.Routes.MapPageRoute(“default”, “{areacode}/{days}”,”~/my.aspx”, false, defaults, constaints, dataTokens);

  my.aspx页面会打字与印刷成功匹配后的路由(RouteData)数据,运维结果展现,即使成功匹配(days由暗中同意值),但是处理页面my.aspx没有体现路由数量。所以要设置

  RouteTable.Routes.RouteExistingFiles =
true;

肆 、注册忽略路由(Ignore)

  IIS7.5以及在合龙格局下,全部请求都要跻身ASP.NET管道,那么大家要过滤掉一部分css和js之类的央浼,不对这个请求实行路由,通过全局路由表RouteCollection的Ignore方法,如下语句

  RouteTable.Routes.Ignore(“css/{filename}.css/{*pathInfo}”);

伍 、路由注册第三种艺术(Add方法)

  RouteTable.Routes.Add(new Route(“{areacode}/{days}”,defaults, constaints,
dataTokens,new PageRouteHandler(“~/my.aspx”, false ));

叁 、依照路由规则生成U福睿斯L

  即便用RouteTable.Routes.GetVirtualPath,通过路由配置生成 U兰德奥迪Q3L
,好处是能够转移配置而无需担心在应用程序中创建的UENCOREL链接中断,上边是3个应用例子:

  private string
GetVirtualPathForRecipe(string
recipeName)

  {

    VirtualPathData pathData = 

      RouteTable.Routes.GetVirtualPath(
      null,
      ”Recipe”,
      new RouteValueDictionary { { “Name”, recipeName } });

    return pathData.VirtualPath;

  }  

  Recipe是路由名称,路由模板为 (/recipe/{name})
,new RouteValueDictionary { { “Name”, recipeName
}是传播的路由变量及其值

  var recipes =
    new RecipeRepository()
      .GetAllRecipeNames()
      .OrderBy(recipeName => recipeName)
      .Select(recipeName =>
        new
        {
          Name = recipeName,
          Url = GetVirtualPathForRecipe(recipeName)
        });

 四 、怎么样获得最后处理请求的HttpHandler(UrlRoutingModule)

  HttpHandler是由以下接口获得的

  public interface IRouteHandler
  {
    IHttpHandler GetHttpHandler(RequestContext requestContext);
  }

  从前方源码,可以领略,路由登记时候就内定了PageRouteHandler作为IRouteHandler,其GetHttpHandler方法会再次来到处理physicalFile的IHttpHandler

  Route route = new Route(routeUrl, defaults, constraints,
dataTokens, (IRouteHandler)new PageRouteHandler(physicalFile,
checkPhysicalUrlAccess));

  那如什么日期候让系统了然,处理当下恳请是用万分Httphandler呢,利用拦截HttpModule来落到实处。UrlRoutingModule就是那一个请求拦截器。定义如下:

  public class UrlRoutingModule : IHttpModule

  {

    public RouteCollection RouteCollection { get; set; }
    protected void Init(HttpApplication context)

    {
      context.PostResolveRequestCache += new EventHandler(this.OnPostResolveRequestCache);
    }
    void
OnPostResolveRequestCache( object o,
EventArgs e)

    {
      HttpContext context =
((HttpApplication)sender).Context;
      HttpContextBase
contextWrapper = new HttpContextWrapper(context);
      //从近日恳请获取路由解析后的数码RouteData
      var routeData = RouteCollection.GetRouteData
(contextWrapper);
      //封装RouteData对象和眼下HttpRequest对象为requestContext
      var requestContext = new
RequestContext (context,
routeData);
      //使用当前RouteData对象中的RouteHander属性获取路由拍卖程序IHttpHander接口
      IHttpHandler httpHandler
= routeData.RouteHandler.GetHttpHandler (requestContext );
      context.Request.RequestContext = requestContext ;
      context.RemapHandler (httpHandler);

     }

  }