本章將講述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扮演的角色。敬請期待。