• 5.路由源码解读


    1.路由学习

    2.路由源码解读

    3.自定义路由

    前面学习如何使用路由,如果不看看底层原理,那么岂不是浑浑噩噩的?还是那一句话所有的扩展,都是基于源代码来的而不是百度(再说看源代码,也可以学习别人的一些设计方式)

    我们都知道我们在Global.asax文件中调用了RouteConfig类中的RegisterRoutes方法,里面传递了一个参数RouteTable.Routes,那么这个是什么了,我们来看看源码:

    namespace System.Web.Routing
    {
          [TypeForwardedFrom("System.Web.Routing, Version=3.5.0.0, Culture=Neutral, PublicKeyToken=31bf3856ad364e35")]
          public class RouteTable
          {
              private static RouteCollection _instance = new RouteCollection();
              public static RouteCollection Routes
              {
                  get
                  {
                     return RouteTable._instance;
                  }
               }
          }
    }

    我们可以看出,此方法返回一个RouteCollection实例,通过名字我们也可以知道,其实这个就是一个装路由的容器

    那么我们在RouteConfig里面注册的路由,有时通过什么方式放入里面了?F12进入你们我们可以看到如下几个方法:

    public static Route MapRoute(this RouteCollection routes, string name, string url);
    public static Route MapRoute(this RouteCollection routes, string name, string url, object defaults);
    public static Route MapRoute(this RouteCollection routes, string name, string url, string[] namespaces);
    public static Route MapRoute(this RouteCollection routes, string name, string url, object defaults, object constraints);
    public static Route MapRoute(this RouteCollection routes, string name, string url, object defaults, string[] namespaces);
    public static Route MapRoute(this RouteCollection routes, string name, string url, object defaults, object constraints, string[] namespaces);

    我们看源码如下:

    // System.Web.Mvc.RouteCollectionExtensions
    public static Route MapRoute(this RouteCollection routes, string name, string url)
    {
        return routes.MapRoute(name, url, null, null);
    }

    其实前面几个重载方法,都是调用最后一个方法,源代码如下:

    // System.Web.Mvc.RouteCollectionExtensions
    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 route = new Route(url, new MvcRouteHandler())
        {
            Defaults = RouteCollectionExtensions.CreateRouteValueDictionaryUncached(defaults),
            Constraints = RouteCollectionExtensions.CreateRouteValueDictionaryUncached(constraints),
            DataTokens = new RouteValueDictionary()
        };
        ConstraintValidation.Validate(route);
        if (namespaces != null && namespaces.Length > 0)
        {
            route.DataTokens["Namespaces"] = namespaces;
        }
        routes.Add(name, route);
        return route;
    }

     我们可以看到里面其中有二行核心代码:

    Route route = new Route(url, new MvcRouteHandler())
    ....
    routes.Add(name, route);

    意思简单明了就是实例化一个路由,然后添加到我们上面说的RouteCollection中,Route源代码如下:

    namespace System.Web.Routing
    {
        [TypeForwardedFrom("System.Web.Routing, Version=3.5.0.0, Culture=Neutral, PublicKeyToken=31bf3856ad364e35")]
        public class Route : RouteBase
        {
            private const string HttpMethodParameterName = "httpMethod";
    
            private string _url;
    
            private ParsedRoute _parsedRoute;
    
            public RouteValueDictionary Constraints
            {
                get;
                set;
            }
    
            public RouteValueDictionary DataTokens
            {
                get;
                set;
            }
    
            public RouteValueDictionary Defaults
            {
                get;
                set;
            }
    
            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 Route(string url, RouteValueDictionary defaults, IRouteHandler routeHandler)
            {
                this.Url = url;
                this.Defaults = defaults;
                this.RouteHandler = routeHandler;
            }
    
            public Route(string url, RouteValueDictionary defaults, RouteValueDictionary constraints, IRouteHandler routeHandler)
            {
                this.Url = url;
                this.Defaults = defaults;
                this.Constraints = constraints;
                this.RouteHandler = routeHandler;
            }
    
            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 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 override VirtualPathData GetVirtualPath(RequestContext requestContext, RouteValueDictionary values)
            {
                BoundUrl boundUrl = this._parsedRoute.Bind(requestContext.RouteData.Values, values, this.Defaults, this.Constraints);
                if (boundUrl == null)
                {
                    return null;
                }
                if (!this.ProcessConstraints(requestContext.HttpContext, boundUrl.Values, RouteDirection.UrlGeneration))
                {
                    return null;
                }
                VirtualPathData virtualPathData = new VirtualPathData(this, boundUrl.Url);
                if (this.DataTokens != null)
                {
                    foreach (KeyValuePair<string, object> current in this.DataTokens)
                    {
                        virtualPathData.DataTokens[current.Key] = current.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 text = constraint as string;
                if (text == null)
                {
                    throw new InvalidOperationException(string.Format(CultureInfo.CurrentUICulture, SR.GetString("Route_ValidationMustBeStringOrCustomConstraint"), new object[]
                    {
                        parameterName,
                        this.Url
                    }));
                }
                object value;
                values.TryGetValue(parameterName, out value);
                string input = Convert.ToString(value, CultureInfo.InvariantCulture);
                string pattern = "^(" + text + ")$";
                return Regex.IsMatch(input, pattern, RegexOptions.IgnoreCase | RegexOptions.CultureInvariant);
            }
    
            private bool ProcessConstraints(HttpContextBase httpContext, RouteValueDictionary values, RouteDirection routeDirection)
            {
                if (this.Constraints != null)
                {
                    foreach (KeyValuePair<string, object> current in this.Constraints)
                    {
                        if (!this.ProcessConstraint(httpContext, current.Value, current.Key, values, routeDirection))
                        {
                            return false;
                        }
                    }
                    return true;
                }
                return true;
            }
        }
    }
    View Code

    首先我们里面的代码什么的都不看,就看它的继承关系

    public class Route : RouteBase

     可以看出它继承于RouteBase,什么是Base,我就不说了哈,都懂的,源代码如下:

    namespace System.Web.Routing
    {
        [TypeForwardedFrom("System.Web.Routing, Version=3.5.0.0, Culture=Neutral, PublicKeyToken=31bf3856ad364e35")]
        public abstract class RouteBase
        {
            private bool _routeExistingFiles = true;
    
            public bool RouteExistingFiles
            {
                get
                {
                    return this._routeExistingFiles;
                }
                set
                {
                    this._routeExistingFiles = value;
                }
            }
    
            public abstract RouteData GetRouteData(HttpContextBase httpContext);
    
            public abstract VirtualPathData GetVirtualPath(RequestContext requestContext, RouteValueDictionary values);
        }
    }

    通过这里其实我们就可以进行扩展了,就是我们创建一个类然后继承于RouteBase,实现里面的抽象方法,然后通过RouteCollection类的add方法把我们定义的路由添加进去。

    可以看出里面的抽象包含二个参数,HttpContextBase  RequestContext,上下文代表着什么,代表着梦想,这里面基本上涵盖了请求的各种信息,也就是我们可以在这两个方法里面做很多很多的事

    我们再来看看Add方法的源码:

    // System.Web.Routing.RouteCollection
    public void Add(string name, RouteBase item)
    {
        if (item == null)
        {
            throw new ArgumentNullException("item");
        }
        if (!string.IsNullOrEmpty(name) && this._namedMap.ContainsKey(name))
        {
            throw new ArgumentException(string.Format(CultureInfo.CurrentUICulture, SR.GetString("RouteCollection_DuplicateName"), new object[]
            {
                name
            }), "name");
        }
        base.Add(item);
        if (!string.IsNullOrEmpty(name))
        {
            this._namedMap[name] = item;
        }
        Route route = item as Route;
        if (route != null && route.RouteHandler != null)
        {
            TelemetryLogger.LogHttpHandler(route.RouteHandler.GetType());
        }
    }

     其中:name参数表示路由的名称(名称只能唯一哦),RouteBase参数表示接受RouteBase的派生类,也就是路由

    其中核心代码如下:

    base.Add(item);

     这个是调用父类的Add方法,我们来看看源码:

    。。。。打住不能看了,跑偏了,就当这个不重要,有兴趣的可以去看看

    this._namedMap[name] = item;

    这个嘛,我们来看看_namedMap是什么东东:

    private Dictionary<string, RouteBase> _namedMap = new Dictionary<string, RouteBase>(StringComparer.OrdinalIgnoreCase);

    前面一直说放入RouteCollection里面,一直不明白(别说你们不想知道),原来是用一个字典存储的啊!!!!

    如果还想更加了解里面的原理机制,可以查看https://www.cnblogs.com/wangiqngpei557/p/3379095.html

  • 相关阅读:
    转-关于图片或者文件在数据库的存储方式归纳
    转-数据流图的画法
    Effective Java2-学习笔记 第11-20条
    Effective Java2-学习笔记 第1-10条
    Python面向对象-学习笔记
    python基础语法-学习笔记
    C# 获取时间戳
    C# 时间格式转换
    C# 获取IP地址
    Http post请求
  • 原文地址:https://www.cnblogs.com/zjdbk/p/10628368.html
Copyright © 2020-2023  润新知