前面学习如何使用路由,如果不看看底层原理,那么岂不是浑浑噩噩的?还是那一句话所有的扩展,都是基于源代码来的而不是百度(再说看源代码,也可以学习别人的一些设计方式)
我们都知道我们在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; } } }
首先我们里面的代码什么的都不看,就看它的继承关系
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
原文地址:https://www.cnblogs.com/zjdbk/p/10628368.html