MVC路由解析---UrlRoutingModule ide
Area的使用工具
前面咱們講了IgnoreRoute連接ui
如今咱們講講核心的MapRoute,仍是提早準備Reflection工具,如果沒準備,能夠看「」MVC路由深刻詳解1---IgnoreRoute」中的System.Web.dll源碼this
咱們來看看RouteCollection.MapRoute,截圖以下:url
相信你們看到了RouteCollectionExtensions是一個靜態類,是對RouteCollection的擴展(關於擴展方法的你們能夠百度,此處不作詳細描述)。好傢伙,咱們看看這個擴展方法走向何方(這個時候就是Reflection發揮做用的時候了)。spa
引用「」MVC路由深刻詳解1---IgnoreRoute」中的內容,看看MapRoute的參數傳入的是什麼:code
name: "Default"orm
url: "{controller}/{action}/{id}"
defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional } --->這是個匿名類型
咱們看看擴展方法去了哪裏:
public static Route MapRoute(this RouteCollection routes, string name, string url, object defaults) => routes.MapRoute(name, url, defaults, null);
咱們接着往下走
public static Route MapRoute(this RouteCollection routes, string name, string url, object defaults, object constraints) =>routes.MapRoute(name, url, defaults, constraints, null);
接着
public Route MapRoute(string name,string url,object defaults,object constraints=null,string[] param=null) { if(url==null) { throw new ArgumentNullException("url"); } Route route = new Route(url, new MvcRouteHandler()) { Defaults=CreateRouteValueDictionaryUncached(defaults), Constraints=CreateRouteValueDictionaryUncached(constraints), DataTokens=new System.Web.Routing.RouteValueDictionary() }; ConstraintValidation.Validate(route); if ((param != null) && (param.Length > 0)) { route.DataTokens["Namespaces"] = param; } Add(name, route); return route; }
上面新建了一個Route,Route就是一條具體的路由 ,new Route(url, new MvcRouteHandler())傳入規則url和new MvcRouteHandler()。
private static System.Web.Routing.RouteValueDictionary CreateRouteValueDictionaryUncached(object values) { IDictionary<string, object> dictionary = values as IDictionary<string, object>; if (dictionary != null) { return new System.Web.Routing.RouteValueDictionary(dictionary); } return System.Web.WebPages.TypeHelper.ObjectToDictionaryUncached(values); }
咱們繼續拆解MvcRouteHandler
public class MvcRouteHandler: System.Web.Routing.IRouteHandler
{
System.Web.Mvc.IControllerFactory _controllerFactory;
public MvcRouteHandler() { } public MvcRouteHandler(System.Web.Mvc.IControllerFactory controllFactory) { _controllerFactory = controllFactory; } protected virtual IHttpHandler GetHttpHandler(System.Web.Routing.RequestContext requestContext) { //SetSessionStateBehavior:在派生類重寫時,設置支持HTTP請求所必須的會話狀態行爲的類型 requestContext.HttpContext.SetSessionStateBehavior(GetSessionStateBehavior(requestContext)); return new MvcHandler(requestContext); } IHttpHandler System.Web.Routing.IRouteHandler.GetHttpHandler(System.Web.Routing.RequestContext requestContext) { return GetHttpHandler(requestContext); } protected virtual System.Web.SessionState.SessionStateBehavior GetSessionStateBehavior(System.Web.Routing.RequestContext requestContext) { string str = (string)requestContext.RouteData.Values["controller"]; if (string.IsNullOrEmpty(str)) { throw new InvalidOperationException(System.Web.Mvc.Properties.MvcResources.MvcRouteHandler_RouteValuesHasNoController); } IControllerFactory factory = _controllerFactory ?? ControllerBuilder.Current.GetControllerFactory(); return factory.GetControllerSessionBehavior(requestContext, str); } }
RouteValueDictionary是對Dictionary<string,object>進行包裝,下面是RouteValueDictionary拆解
public RouteValueDictionary(object values) { this._dictionary = new Dictionary<string, object>(StringComparer.OrdinalIgnoreCase); this.AddValues(values); } private void AddValues(object values) { if (values != null) { foreach (PropertyDescriptor descriptor in TypeDescriptor.GetProperties(values)) { object obj2 = descriptor.GetValue(values); this.Add(descriptor.Name, obj2); } } }
咱們來看看效果
咱們來看看這個Add方法:
public void Add(string name, RouteBase item) { if (item == null) { throw new ArgumentNullException("item"); } if (!string.IsNullOrEmpty(name) && this._namedMap.ContainsKey(name)) { object[] args = new object[] { name }; //throw new ArgumentException(string.Format(CultureInfo.CurrentUICulture, System.Web.SR.GetString("RouteCollection_DuplicateName"), args), "name"); } base.Add(item); if (!string.IsNullOrEmpty(name)) { this._namedMap[name] = item; } }
裏面作了重複路由名稱驗證,Add方法的第二個參數是RouteBase,咱們看看MapRoute方法裏傳入給Add方法的參數是Route。Route是繼承於RouteBase,RouteBase是一個抽象類,這個類是爲繼承類服務的,裏面定義了GetRouteData和GetVirtualPath兩個抽象方法。
GetRouteData:解析請求url,提取數據,如:/home/index 獲得:controller/home,action/index提取獲得的數據會包裝成RouteData
GetVirtualPath:生成URL
public abstract class RouteBase { // Methods protected RouteBase(); public abstract RouteData GetRouteData(HttpContextBase httpContext); public abstract VirtualPathData GetVirtualPath(RequestContext requestContext, RouteValueDictionary values); }
public class Route : RouteBase { // Fields private ParsedRoute _parsedRoute; private string _url; private const string HttpMethodParameterName = "httpMethod"; // Methods public Route(string url, IRouteHandler routeHandler); public Route(string url, RouteValueDictionary defaults, IRouteHandler routeHandler); public Route(string url, RouteValueDictionary defaults, RouteValueDictionary constraints, IRouteHandler routeHandler); public Route(string url, RouteValueDictionary defaults, RouteValueDictionary constraints, RouteValueDictionary dataTokens, IRouteHandler routeHandler); public override RouteData GetRouteData(HttpContextBase httpContext); public override VirtualPathData GetVirtualPath(RequestContext requestContext, RouteValueDictionary values); protected virtual bool ProcessConstraint(HttpContextBase httpContext, object constraint, string parameterName, RouteValueDictionary values, RouteDirection routeDirection); private bool ProcessConstraints(HttpContextBase httpContext, RouteValueDictionary values, RouteDirection routeDirection); // Properties public RouteValueDictionary Constraints { get; set; } public RouteValueDictionary DataTokens { get; set; } public RouteValueDictionary Defaults { get; set; } public IRouteHandler RouteHandler { get; set; } public string Url { get; set; } }
Route添加了幾個屬性
Constraints:保存約束規則,最終保存爲RouteValueDictionary
DataTokens:附加參數,指定controller的空間命名也放在這裏。
Defaults:保存規則的默認值
url:規則URL
咱們來看看GetRouteData,咱們看看RouteData routeData=RouteCollection.GetRouteData(context)。
public RouteData GetRouteData(HttpContextBase httpContext) { if (httpContext == null) { throw new ArgumentNullException("httpContext"); } if (httpContext.Request == null) { throw new ArgumentException(RoutingResources.RouteTable_ContextMissingRequest, "httpContext"); } if (!this.RouteExistingFiles) { string appRelativeCurrentExecutionFilePath = httpContext.Request.AppRelativeCurrentExecutionFilePath; if (((appRelativeCurrentExecutionFilePath != "~/") && (this._vpp != null)) && (this._vpp.FileExists(appRelativeCurrentExecutionFilePath) || this._vpp.DirectoryExists(appRelativeCurrentExecutionFilePath))) { return null; } } using (this.GetReadLock()) { foreach (RouteBase base2 in this) { RouteData routeData = base2.GetRouteData(httpContext); if (routeData != null) { return routeData; } } } return null; }
上述代碼中最後經過遞歸遍歷本身全部的路由規則,分別調用咱們全部註冊在RouteTable.Routes--->RouteCollection。
咱們還注意到上面有這麼一段:
RouteCollection 有這麼一個屬性RouteExistingFiles.當爲false時,就檢測請求的路徑地址是否己經存在文件或目錄,若是存在,則直接不走路由了,直接返回null,默認就是false,咱們能夠實驗一下。固然這裏是忽略了根目錄的,否則默認咱們 http://www.xxx.com/ 也不能訪問了。
這裏是默認的路由註冊,按理說咱們訪問 home 時,會去到 home controller 的 index,可是咱們在在項目里加一個 home 目錄,以下圖。
咱們再訪問:http://localhost:2144/home/ 咱們發現,沒法找到該資源,也就是檢測到home這個目錄存在時,就不走路由了。
爲尊重原創,本文的編寫參考瞭如下博文和文章:
程序園: http://www.cnblogs.com/lindaohui/archive/2012/08/31/2664047.html