在看那一个注册的格局从前,  ASP.NET路由系统包蕴两上面选取

从日前篇章的分析, 其实能看的出来, IHttpModule 能够注册成都百货上千个,
而且能够从web.config注册, 能够动态注册. 可是有三个重头戏的Module没有讲,
那里就先来讲一下这些大旨的Module — UrlRoutingModule

以前面篇章的辨析, 其实能看的出来, IHttpModule 能够注册成都百货上千个,
而且能够从web.config注册, 能够动态注册. 但是有四个主体的Module没有讲,
那里就先来讲一下这么些重点的Module — UrlRoutingModule

 

[TypeForwardedFrom("System.Web.Routing, Version=3.5.0.0, Culture=Neutral, PublicKeyToken=31bf3856ad364e35")]
public class UrlRoutingModule : IHttpModule
{
    // Fields
    private static readonly object _contextKey;
    private static readonly object _requestDataKey;
    private RouteCollection _routeCollection;

    // Methods
    static UrlRoutingModule();
    [TargetedPatchingOptOut("Performance critical to inline this type of method across NGen image boundaries")]
    public UrlRoutingModule();
    protected virtual void Dispose();
    protected virtual void Init(HttpApplication application);
    private void OnApplicationPostResolveRequestCache(object sender, EventArgs e);
    [Obsolete("This method is obsolete. Override the Init method to use the PostMapRequestHandler event.")]
    public virtual void PostMapRequestHandler(HttpContextBase context);
    public virtual void PostResolveRequestCache(HttpContextBase context);
    [TargetedPatchingOptOut("Performance critical to inline this type of method across NGen image boundaries")]
    void IHttpModule.Dispose();
    [TargetedPatchingOptOut("Performance critical to inline this type of method across NGen image boundaries")]
    void IHttpModule.Init(HttpApplication application);

    // Properties
    public RouteCollection RouteCollection { get; [TargetedPatchingOptOut("Performance critical to inline this type of method across NGen image boundaries")] set; }
}
[TypeForwardedFrom("System.Web.Routing, Version=3.5.0.0, Culture=Neutral, PublicKeyToken=31bf3856ad364e35")]
public class UrlRoutingModule : IHttpModule
{
    // Fields
    private static readonly object _contextKey;
    private static readonly object _requestDataKey;
    private RouteCollection _routeCollection;

    // Methods
    static UrlRoutingModule();
    [TargetedPatchingOptOut("Performance critical to inline this type of method across NGen image boundaries")]
    public UrlRoutingModule();
    protected virtual void Dispose();
    protected virtual void Init(HttpApplication application);
    private void OnApplicationPostResolveRequestCache(object sender, EventArgs e);
    [Obsolete("This method is obsolete. Override the Init method to use the PostMapRequestHandler event.")]
    public virtual void PostMapRequestHandler(HttpContextBase context);
    public virtual void PostResolveRequestCache(HttpContextBase context);
    [TargetedPatchingOptOut("Performance critical to inline this type of method across NGen image boundaries")]
    void IHttpModule.Dispose();
    [TargetedPatchingOptOut("Performance critical to inline this type of method across NGen image boundaries")]
    void IHttpModule.Init(HttpApplication application);

    // Properties
    public RouteCollection RouteCollection { get; [TargetedPatchingOptOut("Performance critical to inline this type of method across NGen image boundaries")] set; }
}

  ASP.NET Web API 要是利用Web Host格局来过夜,在伏乞进入Web API
音信处理管道在此之前,就会用ASP.NET
本人的路由系统基于登记的路由表,解析出近期央浼的HttpController和Action的名称,以及与对象Action方法有些参数实行绑定的路由变量。

来看一下她的Init方法, 注册了怎么进去.

来看一下他的Init方法, 注册了哪些进去.

  ASP.NET路由系统包涵两下面选取:

protected virtual void Init(HttpApplication application)
{
    if (application.Context.Items[_contextKey] == null)
    {
        application.Context.Items[_contextKey] = _contextKey;
        application.PostResolveRequestCache += new EventHandler(this.OnApplicationPostResolveRequestCache);
    }
}
protected virtual void Init(HttpApplication application)
{
    if (application.Context.Items[_contextKey] == null)
    {
        application.Context.Items[_contextKey] = _contextKey;
        application.PostResolveRequestCache += new EventHandler(this.OnApplicationPostResolveRequestCache);
    }
}
  • 注册路由映射,即注册路由模板和大体文件的协作关系,达成请求URubiconL地址和处理请求的大体地址的离别,能够增强请求USportageL可读性,SEO优化,灵活性,即请求UCR-VL和处理请求的大体文件的变型互不影响
  • UCR-VL生成,依照登记的路由规则变更对应UTiguanL,使用那种U中华VL,刚好利用了路由登记的百发百中,可以使原来生成的U翼虎L不暂停,只需求修改路由布置的拍卖公事。

从上一篇的不得了事件图上能够观望, 那个是注册在缓存检查完结的轩然大波上.
在看这些注册的点子从前, 还需求讲点其余. 因为在实施那几个办法从前, 先执行的
Application_Start方法, 在那几个格局中, 大家创建了路由表.
并在路由表中到场了相当的路由规则.

从上一篇的尤其事件图上能够看出, 这些是挂号在缓存检查得了的轩然大波上.
在看那么些注册的措施此前, 还索要讲点别的. 因为在推行那一个办法从前, 先执行的
Application_Start方法, 在这些格局中, 大家创立了路由表.
并在路由表中到场了合营的路由规则.

① 、涉及的类及源码分析

这先来讲一下路由登记吧.

那先来讲一下路由注册吧.

  涉及的重大项目都在System.Web.Routing中,类及重点成员和相互关系如下图:

一 、路由注册

壹 、路由注册

   图片 1

 路由登记那里, 分为一般理由注册,区域路由注册,api路由注册.
那里只介绍一般路由登记, 其实是平等的, 只是注册的非常规则不一而已.

 路由登记那里, 分为一般理由注册,区域路由登记,api路由注册.
那里只介绍一般路由注册, 其实是一样的, 只是注册的合营规则不一而已.

1、RouteBase

在Application_Start方法中, 路由登记正是上边那句话了.

在Application_Start方法中, 路由登记正是上面那句话了.

  public abstract class RouteBase
  {
    private bool _routeExistingFiles = true;
    //依照路由模板与请求的UENVISIONL举办匹配,借使成功再次回到RouteData,不然再次回到NULL
    public abstract RouteData GetRouteData(HttpContextBase httpContext);
    //选取钦命的路由变量列表(包涵名称和值)与U陆风X8L路由模板进行匹配,若匹配成功,再次回到完整USportageL,不然再次来到NULL
    public abstract VirtualPathData GetVirtualPath(RequestContext requestContext, RouteValueDictionary values);
    //表示是不是对现有的大体文件实施路由,默许值为true,即经过地方“/employees/hr/index.aspx”
是造访不到 Index.aspx页面

RouteConfig.RegisterRoutes(RouteTable.Routes);
RouteConfig.RegisterRoutes(RouteTable.Routes);

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

先来看一下, 那几个主意的参数.

先来看一下, 那么些情势的参数.

2、Route

// 摘要: 
//     存储应用程序的 URL 路由。
[TypeForwardedFrom("System.Web.Routing, Version=3.5.0.0, 
  Culture=Neutral, PublicKeyToken=31bf3856ad364e35")]
public class RouteTable
{
    // 摘要: 
    //     初始化 System.Web.Routing.RouteTable 类的新实例。
    public RouteTable();

    // 摘要: 
    //     获取从 System.Web.Routing.RouteBase 类派生的对象的集合。
    //
    // 返回结果: 
    //     包含集合中的所有路由的对象。
    public static RouteCollection Routes { get; }
}
// 摘要: 
//     存储应用程序的 URL 路由。
[TypeForwardedFrom("System.Web.Routing, Version=3.5.0.0, 
  Culture=Neutral, PublicKeyToken=31bf3856ad364e35")]
public class RouteTable
{
    // 摘要: 
    //     初始化 System.Web.Routing.RouteTable 类的新实例。
    public RouteTable();

    // 摘要: 
    //     获取从 System.Web.Routing.RouteBase 类派生的对象的集合。
    //
    // 返回结果: 
    //     包含集合中的所有路由的对象。
    public static RouteCollection Routes { get; }
}

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

从那边能来看, 其实他传的是一个静态路由集合, 封装成了1个路由表.

从那边能收看, 其实他传的是二个静态路由集合, 封装成了叁个路由表.

  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;
    }

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 },
        constraints: new { controller=@"^\w+$", id=@"^\d+$" } //可以不写, 这里是对名称和参数的约束
    );
}
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 },
        constraints: new { controller=@"^\w+$", id=@"^\d+$" } //可以不写, 这里是对名称和参数的约束
    );
}

    //为路由模板中的变量以正则表明式的形武设定一些束缚规范,Key为变量名,Value为正则表明式

此处的IgnoreRoute就不看了,
直接看MapRoute方法, 这几个点子是存放在在静态扩大类中的:
RouteCollectionExtensions 

此处的IgnoreRoute就不看了,
直接看MapRoute方法, 那么些主意是存放在静态扩充类中的:
RouteCollectionExtensions 

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

中间有那多少个的重载, 我只看那多少个参数最多的主意吧.

内部有不少的重载, 笔者只看那多个参数最多的艺术吧.

    public IRouteHandler RouteHandler { get; set; }

public static Route MapRoute(this RouteCollection routes, string name, string url, 
                    object defaults, object constraints, string[] namespaces)
{
    if (routes == null)
    {
        throw new ArgumentNullException("routes");
    }
    if (url == null)
    {
        throw new ArgumentNullException("url");
    }
    Route item = new Route(url, new MvcRouteHandler()) {
        Defaults = CreateRouteValueDictionary(defaults),
        Constraints = CreateRouteValueDictionary(constraints),
        DataTokens = new RouteValueDictionary()
    };
    if ((namespaces != null) && (namespaces.Length > 0))
    {
        item.DataTokens["Namespaces"] = namespaces;
    }
    routes.Add(name, item);
    return item;
}
public static Route MapRoute(this RouteCollection routes, string name, string url, 
                    object defaults, object constraints, string[] namespaces)
{
    if (routes == null)
    {
        throw new ArgumentNullException("routes");
    }
    if (url == null)
    {
        throw new ArgumentNullException("url");
    }
    Route item = new Route(url, new MvcRouteHandler()) {
        Defaults = CreateRouteValueDictionary(defaults),
        Constraints = CreateRouteValueDictionary(constraints),
        DataTokens = new RouteValueDictionary()
    };
    if ((namespaces != null) && (namespaces.Length > 0))
    {
        item.DataTokens["Namespaces"] = namespaces;
    }
    routes.Add(name, item);
    return item;
}

    //路由模板,如/weather/{areacode}/{days},请求的U本田CR-VL就是跟该模板举办匹配,/分割成三个段,每种段又分变量(areacode,days)和字面量(weather)

此间正是分析参数, 并创制路由存入路由集合中, 即存入路由表中.

那边就是分析参数, 并创立路由存入路由集合中, 即存入路由表中.

    //匹配的八个标准,段数和路由模板相同,以及对应文本段内容也要平等,注,U奥迪Q3L大小写不灵活
    public string Url
    {
      get
      {
        return this._url ?? string.Empty;
      }
      set
      {
        this._parsedRoute =
RouteParser.Parse(value);
        this._url = value;
      }
    }

  1. 那边现身了贰个 MvcRouteHandler的东东, 名字感觉跟MVC有点关系了,
    那进去瞧瞧?

    public class MvcRouteHandler : IRouteHandler
    {

     // Fields
     private IControllerFactory _controllerFactory;
    
     // Methods
     public MvcRouteHandler();
     public MvcRouteHandler(IControllerFactory controllerFactory);
     protected virtual IHttpHandler GetHttpHandler(RequestContext requestContext);
     protected virtual SessionStateBehavior GetSessionStateBehavior(RequestContext requestContext);
     IHttpHandler IRouteHandler.GetHttpHandler(RequestContext requestContext);
    

    }

  1. 此处出现了3个 MvcRouteHandler的东东, 名字感觉跟MVC有点关系了,
    那进去瞧瞧?

    public class MvcRouteHandler : IRouteHandler
    {

     // Fields
     private IControllerFactory _controllerFactory;
    
     // Methods
     public MvcRouteHandler();
     public MvcRouteHandler(IControllerFactory controllerFactory);
     protected virtual IHttpHandler GetHttpHandler(RequestContext requestContext);
     protected virtual SessionStateBehavior GetSessionStateBehavior(RequestContext requestContext);
     IHttpHandler IRouteHandler.GetHttpHandler(RequestContext requestContext);
    

    }

    //根据路由模板与请求的U中华VL进行匹配,假使成功再次回到RouteData,不然重回NULL

以此GetHttpHandler里面, 有让人激动的东东哦, 先看一下啊, 不继续助教了

本条GetHttpHandler里面, 有令人震撼的东东哦, 先看一下吗, 不继续上课了

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

protected virtual IHttpHandler GetHttpHandler(RequestContext requestContext)
{
    requestContext.HttpContext.SetSessionStateBehavior(this.GetSessionStateBehavior(requestContext));
    return new MvcHandler(requestContext);
}
protected virtual IHttpHandler GetHttpHandler(RequestContext requestContext)
{
    requestContext.HttpContext.SetSessionStateBehavior(this.GetSessionStateBehavior(requestContext));
    return new MvcHandler(requestContext);
}
  • 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;
        }

 

 

    //选拔钦定的路由变量列表(包涵名称和值)与U卡宴L路由模板实行匹配,若匹配成功,再次回到完整U昂科雷L,不然重返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;
    }

  1. 此处怎么defaults和 constraints 都存成 CreateRouteValueDictionary
    类型呢, 那里临时只看一下他存放到哪儿吧.

    private static RouteValueDictionary CreateRouteValueDictionary(object values)
    {

     IDictionary<string, object> dictionary = values as IDictionary<string, object>;
     if (dictionary != null)
     {
         return new RouteValueDictionary(dictionary);
     }
     return new RouteValueDictionary(values);
    

    }

    public RouteValueDictionary(object values)
    {

     this._dictionary = new Dictionary<string, object>(StringComparer.OrdinalIgnoreCase);
     this.AddValues(values);
    

    }

  1. 此处怎么defaults和 constraints 都存成 CreateRouteValueDictionary
    类型呢, 那里一时半刻只看一下她存放到何地吧.

    private static RouteValueDictionary CreateRouteValueDictionary(object values)
    {

     IDictionary<string, object> dictionary = values as IDictionary<string, object>;
     if (dictionary != null)
     {
         return new RouteValueDictionary(dictionary);
     }
     return new RouteValueDictionary(values);
    

    }

    public RouteValueDictionary(object values)
    {

     this._dictionary = new Dictionary<string, object>(StringComparer.OrdinalIgnoreCase);
     this.AddValues(values);
    

    }

    //处理约束
    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);
    }

从此间看, defaults, constraints , DataTokens 都以一律的类型.

从此间看, defaults, constraints , DataTokens 都以一样的类型.

    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;
    }

等背后要用的时候, 再去分析吧. 

等前面要用的时候, 再去分析吧. 

  }

这一篇算是与MVC挂上钩了, 下一篇就正式进入MVC环节的解析.

这一篇算是与MVC挂上钩了, 下一篇就规范进入MVC环节的解析.

  此外,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通过对请求U汉兰达L的分析获得的
    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对象,并传到给定的参数调用同名方法直到找到2个特出的Route(再次来到值不为Null),并回到相应的RouteData和VirtaulPathData对象,借使集合中其余三个Route都不般配,最后回到NULL

  读写锁的运用:

    RouteCollection那个集合对象不是线程安全的,使用里德rWriterLockSlim进行线程读写同步,四个线程能够同时读,其余情状都不允许,三个线程写时,别的的线程不可能读或写,四个线程在读时候,别的线程只好读,不能够写,即八个线程只可以读读,不可能读写、写写;

    在对聚集举办读取或更新时候,会调用GetReadLock和GetWriteLock方法得到读锁或写锁,重回的是内嵌私有类型:ReadLockDispsoabled和WriteLockDispsoabled,他们达成了接口IDispsoabled,是对ReaderWriterLockSlim的读写锁功效的包装。

  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

  除了用正则表明式对有些变量实行约束外,还是能用三个落实了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,是或不是核对路由目的地址的UOdysseyL授权,暗中同意值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中华VL模板和乞请U本田CR-VL匹配,不然不会获取RouteData数据。

  如大家按古板办法访问3个大体文件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;

4、注册忽略路由(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 ));

叁 、根据路由规则生成URubiconL

  尽管用RouteTable.Routes.GetVirtualPath,通过路由配置生成 U奥迪Q5L
,好处是能够更改配置而无需担心在应用程序中创制的U福特ExplorerL链接中断,上面是八个运用例子:

  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);

     }

  }

 

相关文章