首页 > 代码库 > ASP.NET MVC 路由系统类

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

 

ASP.NET MVC 路由系统类