本章將講述ASP.NET MVC5 的路由原理,即URL映射機制。
簡單點就是解釋:為什么MVC在瀏覽器輸入地址就能訪問到類(或類中的方法)?這是怎么做到的?我自己可以通過.NET寫出一個自己的MVC框架嗎?
答案是:可以。
模擬URL映射
先來看一個Demo,在傳統的.NET WebForms項目中,實現URL的攔截。
打開VS2013,新建一個“ASP.NET Web窗體應用程序”項目,並取名為Demo4URLRouting。
為了方便測試,注釋掉Default.aspx頁面的內容和模板引用。這樣做以后,看起來是這樣
然后新建一個ControllerFactory類,實現IHttpHandler接口。

1 using System; 2 using System.Collections.Generic; 3 using System.Linq; 4 using System.Web; 5 6 namespace Demo4URLRouting 7 { 8 /// <summary> 9 /// 自己寫的ControllerFactory,試圖扮演MVC5中的RouteConfig(路由配置)角色。 10 /// </summary> 11 public class ControllerFactory : IHttpHandler 12 { 13 ControllerFactory() 14 { 15 } 16 17 public bool IsReusable 18 { 19 get; 20 set; 21 } 22 23 public void ProcessRequest(HttpContext context) 24 { 25 context.Response.Write(string.Format("ControllerFactory來攔截請求-> URL為: {0}",context.Request.RawUrl)); 26 } 27 } 28 }
下一步,打開Web.config配置文件,在system.webServer節點下添加一項handlers配置
代碼如下:

<!--for url routing test Start--> <handlers> <add name="ControllerFactory" verb="*" path="*Account/*" type="Demo4URLRouting.ControllerFactory,Demo4URLRouting" preCondition="integratedMode"/> </handlers> <!--for url routing test End-->
此配置的意圖是:攔截站點URL中包含Account關鍵字的全部URL地址。
按F5運行項目,在地址欄站點后,輸入account,發現已成功被ControllerFactory類攔截。
繼續,輸入/account/login。發現地址未被攔截。而是跳轉到了默認項目的登陸頁面。
怎么回事呢?
原來,是項目下的Global.asax文件中的內容引起,注釋掉RouteConfig注冊的路由。
重新輸入/account/login,發現已成功被ControllerFactory類攔截。
現在我們修改下ControllFactory類中ProcessRequest方法的代碼,實現URL和類及類中方法的映射。(注意,代碼做了非常簡單的處理,我們假定忽略大小寫因素,路由格式也和傳統MVC類似)

1 public void ProcessRequest(HttpContext context) 2 { 3 context.Response.Write(string.Format("ControllerFactory來攔截請求-> URL為: {0}",context.Request.RawUrl)); 4 context.Response.Write("<br/>"); 5 6 /** 7 * 將攔截的URL地址分發給對應的Controller 8 **/ 9 //簡單處理,截取URL中第一個/和/之間的字符串做為要查找的Controller對象 10 string url = context.Request.RawUrl; 11 string actionURL = url.IndexOf('?') > 0 ? url.Substring(0, url.IndexOf('?')) : url.Substring(0); 12 string[] strArray = actionURL.Split('/'); 13 //得到類名稱 14 string targetClassName = (strArray[1] + "Controller"); 15 string methodName = string.Empty; 16 if (strArray.Length > 2 && !string.IsNullOrEmpty(strArray[2])) 17 methodName = strArray[2];//以'/'做分割,類名稱后為方法名稱 18 /** 19 * 從URL獲取類名稱之后,利用反射實現方法的調用。 20 **/ 21 //獲取Controller實例 22 object instance = Activator.CreateInstance(Type.GetType(string.Format("Demo4URLRouting.Controllers.{0}", targetClassName))); 23 if (instance != null) 24 { 25 object outputObj = null;//方法輸出內容 26 if (string.IsNullOrEmpty(methodName) || instance.GetType().GetMethod(methodName) == null) 27 methodName = "Index";//如果url沒有輸入方法或方法不存在,默認調用Index方法 28 try 29 { 30 //調用實例方法 31 outputObj = instance.GetType().GetMethod(methodName).Invoke(instance, null); 32 context.Response.Write(outputObj); 33 } 34 catch(MissingMethodException mme) 35 { 36 context.Response.Write(string.Format("<font color='red'>Error! Method not Found!</font> {0}",mme.Message)); 37 } 38 } 39 }
在代碼中,進行了簡單的url分析,獲取類名和方法名,再通過反射機制,實現調用。
然后,為了配合測試,我們在解決方案中新建一個Controllers文件夾,在該文件夾下新建一個類AccountController,代碼如下

using System; using System.Collections.Generic; using System.Linq; using System.Web; namespace Demo4URLRouting.Controllers { public class AccountController { public string Index() { return "this is the AccountController,<b>Index</b> method."; } public string HelloWorld() { return "this is <font color='red'>HelloWorld method</font> which is in the Class named AccountController."; } } }
AccountController類中定義了兩個方法,Index()和HelloWorld()。然后我們通過瀏覽器進行訪問
可以看到,通過在瀏覽器地址中,輸入/Account,實現對AccountController類中Index方法的訪問;輸入/Account/HelloWorld實現對AccountController類中的HelloWorld方法的訪問。
到此,我們初步實現了在WebForms環境下,URL到類的映射。此過程的核心是handlers的配置和利用反射原理調用類中的方法。Demo的不足是沒有去消除大小寫問題,沒有更靈活的路由配置等。
那么問題來了,MVC中這一整套URL映射的機制,是如何實現的呢?
MVC5 URL映射機制
實際上,在寫本篇文章之前,我翻看了大量網上有關MVC的資料,發現大多數對MVC映射機制(也叫MVC路由機制)的描述都非常籠統。
類似不懂裝懂,或者讓你去理解Model-View-Controller的三層,什么業務分離,或者說了半天說一堆廢話。。。我是深惡痛絕的。如果僅僅是解釋微軟MSDN上能查到的東西?那你的解釋意義在哪里?不說了,泡沫信息太多了。
在了解MVC URL映射機制這一套原理之前,你首先要了解ASP.NET Routing。 ASP.NET Routing是.NET的一套獨立組件。總的來說,它可以做兩件事情:
1. 將URL請求地址的片段轉交到handler處理;
2. 構造(創建)URL地址。
Routing目前的信息實在太少,感興趣的可以在MSDN上做初步了解。總的來說,Routing做了我們前面模擬做的所有事情,而且毋庸置疑,做的更好更強大。
在MVC中,從URL到Controller,簡要過程大概是這樣:
URL --> RouteData對象 --> MvcHandler對象 --> IControllerFactory接口 --> Controller
這個過程很復雜,要詳細闡述其過程,估計要三篇文章以上的篇幅。這里就不再闡述。
MVC框架中,RouteConfig類中這段代碼已經做了URL到Controller映射的所有工作。你所需要做的,只是匹配Controller了。

public class RouteConfig { public static void RegisterRoutes(RouteCollection routes) { routes.IgnoreRoute("{resource}.axd/{*pathInfo}"); routes.MapRoute( name: "Default", url: "{controller}/{action}/{id}", defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional } ); } }
總結
本篇文章重點講述了ASP.NET MVC中的URL映射機制。先是通過在WebForms中模擬URL映射,讓初學者有一個直觀的認識。然后簡要的介紹了MVC中URL映射的機制。由於篇幅所限,在介紹URL映射機制時,只做了簡要的闡述。因為知識量很大,而且建議讀者要有ASP.NET Routing組件的基礎。關於Routing組件,以后有空的話,我再單獨寫文章來講。
在下一篇文章中,我將講述Controller的實際應用及擴展,項目中Controller扮演的角色。敬請期待。