ASP.NET MVC 路由系统类

RouteData

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

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

        public string GetRequiredString(string valueName)
        {
            object obj2;
            if (this.Values.TryGetValue(valueName, out obj2))
            {
                string str = obj2 as string;
                if (!string.IsNullOrEmpty(str))
                {
                    return str;
                }
            }
            throw new InvalidOperationException(string.Format(CultureInfo.CurrentUICulture, System.Web.SR.GetString("RouteData_RequiredValue"), new object[] { valueName }));
        }

        public RouteValueDictionary DataTokens
        {
            [TargetedPatchingOptOut("Performance critical to inline this type of method across NGen image boundaries")]
            get
            {
                return this._dataTokens;
            }
        }

        public RouteBase Route
        {
            get
            {
                return this.<Route>k__BackingField;
            }
            set
            {
                this.<Route>k__BackingField = value;
            }
        }

        public IRouteHandler RouteHandler
        {
            get
            {
                return this._routeHandler;
            }
            set
            {
                this._routeHandler = value;
            }
        }

        public RouteValueDictionary Values
        {
            get
            {
                return this._values;
            }
        }
    }
View Code

     RouteData 封装有关路由的信息的类;属性DataTokens是个字典集合,主要存储传递到路由处理程序但未使用的自定义值的集合。比如说Namespace等;

属性Route表示当前的路由的对象,属性Values表示的是路由的 URL 参数值和默认值的集合。属性RouteHandler是继承IRouteHandler的接口的类,在IRouteHandler接口中的GetHttpHandler方法获取到处理页面请求的IHttpHandler;在MVC中RouteData的对象的RouteHandler一般为MvcRouteHandler或是StopRoutingHandler

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

RouteBase

    public abstract class RouteBase
    {
        private bool _routeExistingFiles = true;
        protected RouteBase()
        {
        }
        // 当在派生类中重写时,会返回有关请求的路由信息。
        public abstract RouteData GetRouteData(HttpContextBase httpContext);
//当在派生类中重写时,会检查路由是否与指定值匹配,如果匹配,则生成一个 URL,然后检索有关该路由的信息
public abstract VirtualPathData GetVirtualPath(RequestContext requestContext, RouteValueDictionary values); public bool RouteExistingFiles// 如果 ASP.NET 路由操作处理所有请求(甚至包括与现有文件匹配的请求),则为 true;否则为 false。 默认值为 false。 { get { return this._routeExistingFiles; } set { this._routeExistingFiles = value; } } }
RouteBase 为Route的抽象基类,有2个抽象方法GetRouteData获取当前的RouteDataGetVirtualPath方法获取相关的虚拟url;

Route

  Route类提供用于定义路由及获取路由相关信息的属性和方法,Route类继承了RouteBase 类,并重写了RouteBase 中的GetRouteData方法和GetVirtualPath方法;

public class Route : RouteBase
    {
        private ParsedRoute _parsedRoute;
        private string _url;
        private const string HttpMethodParameterName = "httpMethod";
        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 values = this._parsedRoute.Match(virtualPath, this.Defaults);
            if (values == null)
            {
                return null;
            }
            RouteData data = new RouteData(this, this.RouteHandler);
            if (!this.ProcessConstraints(httpContext, values, RouteDirection.IncomingRequest))
            {
                return null;
            }
            foreach (KeyValuePair<string, object> pair in values)
            {
                data.Values.Add(pair.Key, pair.Value);
            }
            if (this.DataTokens != null)
            {
                foreach (KeyValuePair<string, object> pair2 in this.DataTokens)
                {
                    data.DataTokens[pair2.Key] = pair2.Value;
                }
            }
            return data;
        }

        public override VirtualPathData GetVirtualPath(RequestContext requestContext, RouteValueDictionary values)
        {
            BoundUrl url = this._parsedRoute.Bind(requestContext.RouteData.Values, values, this.Defaults, this.Constraints);
            if (url == null)
            {
                return null;
            }
            if (!this.ProcessConstraints(requestContext.HttpContext, url.Values, RouteDirection.UrlGeneration))
            {
                return null;
            }
            VirtualPathData data = new VirtualPathData(this, url.Url);
            if (this.DataTokens != null)
            {
                foreach (KeyValuePair<string, object> pair in this.DataTokens)
                {
                    data.DataTokens[pair.Key] = pair.Value;
                }
            }
            return data;
        }
        protected virtual bool ProcessConstraint(HttpContextBase httpContext, object constraint, string parameterName, RouteValueDictionary values, RouteDirection routeDirection)
        {
            object obj2;
            IRouteConstraint constraint2 = constraint as IRouteConstraint;
            if (constraint2 != null)
            {
                return constraint2.Match(httpContext, this, parameterName, values, routeDirection);
            }
            string str = constraint as string;
            if (str == null)
            {
                throw new InvalidOperationException(string.Format(CultureInfo.CurrentUICulture, System.Web.SR.GetString("Route_ValidationMustBeStringOrCustomConstraint"), new object[] { parameterName, this.Url }));
            }
            values.TryGetValue(parameterName, out obj2);
            string input = Convert.ToString(obj2, CultureInfo.InvariantCulture);
            string pattern = "^(" + str + ")$";
            return Regex.IsMatch(input, pattern, RegexOptions.CultureInvariant | RegexOptions.IgnoreCase);
        }

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

        public RouteValueDictionary Constraints
        {
            get
            {
                return this.<Constraints>k__BackingField;
            }
            set
            {
                this.<Constraints>k__BackingField = value;
            }
        }

        public RouteValueDictionary DataTokens
        {
         
            get
            {
                return this.<DataTokens>k__BackingField;
            }
            set
            {
                this.<DataTokens>k__BackingField = value;
            }
        }

        public RouteValueDictionary Defaults
        {
           
            get
            {
                return this.<Defaults>k__BackingField;
            }
            set
            {
                this.<Defaults>k__BackingField = value;
            }
        }

        public IRouteHandler RouteHandler
        {
            
            get
            {
                return this.<RouteHandler>k__BackingField;
            }
            set
            {
                this.<RouteHandler>k__BackingField = value;
            }
        }

        public string Url
        {
            get
            {
                return (this._url ?? string.Empty);
            }
            set
            {
                this._parsedRoute = RouteParser.Parse(value);
                this._url = value;
            }
        }
    }
View Code

在我们调用的   routes.MapRoute方法时Route对象被创建;

属性Url:获取或设置路由的 URL 模式。
属性Constraints:取或设置为 URL 参数指定有效值的表达式的词典。添加到Constraints字典中的数据,必须是字符串或是满足IRouteConstraint接口的类;

属性DataTokens: 获取或设置传递到路由处理程序但未用于确定该路由是否匹配 URL 模式的自定义值。比如Namespace,Area等数据;对应于RouteData中的DataTokens;

属性 Defaults:获取或设置要在 URL 不包含所有参数时使用的值,

属性 RouteHandler:对应于RouteData中的RouteHandler;

关于 Route中的GetRouteData方法的执行过程可以参考dz45693写的asp.net mvc源码分析-Route的GetRouteData

RouteCollection

RouteCollection类是存储route的集合,在RouteCollection中存在GetRouteData方法时获取匹配当前的路由;

 

public class RouteCollection : Collection<RouteBase>
{
      .............
    
        public RouteData GetRouteData(HttpContextBase httpContext)
        {
            if (httpContext == null)
            {
                throw new ArgumentNullException("httpContext");
            }
            if (httpContext.Request == null)
            {
                throw new ArgumentException(System.Web.SR.GetString("RouteTable_ContextMissingRequest"), "httpContext");
            }
            if (base.Count != 0)
            {
                bool flag = false;
                bool flag2 = false;
                if (!this.RouteExistingFiles)
                {
                    flag = this.IsRouteToExistingFile(httpContext);
                    flag2 = true;
                    if (flag)
                    {
                        return null;
                    }
                }
                using (this.GetReadLock())
                {
                    foreach (RouteBase base2 in this)
                    {
                        RouteData routeData = base2.GetRouteData(httpContext);
                        if (routeData != null)
                        {
                            if (!base2.RouteExistingFiles)
                            {
                                if (!flag2)
                                {
                                    flag = this.IsRouteToExistingFile(httpContext);
                                    flag2 = true;
                                }
                                if (flag)
                                {
                                    return null;
                                }
                            }
                            return routeData;
                        }
                    }
                }
            }
            return null;
        }


      ..............
}

 

 

      在RouteCollection.GetRouteData方法时,会循环变量当前的RouteCollection中的Route集合,如果能找到匹配的RouteData的话,直接返回,终止循环,从这里可以看出在定义Route的顺序很重要,尽量特殊的匹配

规则写在前面;

RouteTable

RouteTable类很简单,就是包含一个RouteCollection类

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

        public static RouteCollection Routes
        {
            [TargetedPatchingOptOut("Performance critical to inline this type of method across NGen image boundaries")]
            get
            {
                return _instance;
            }
        }
    }

 

郑重声明:本站内容如果来自互联网及其他传播媒体,其版权均属原媒体及文章作者所有。转载目的在于传递更多信息及用于网络分享,并不代表本站赞同其观点和对其真实性负责,也不构成任何其他建议。