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

相关文章: