首页 > 代码库 > 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; } } }
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获取当前的RouteData ,GetVirtualPath方法获取相关的虚拟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; } } }
在我们调用的 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 路由系统类