Routing
到目前為止,我們已經解決了MVC的很多問題,但忽略了最基本的最重要的一個問題:當用戶發送請求時,會發生什么?
最好的答案是“執行Action 方法”,但仍存在疑問:對於一個特定的URL請求,如何確定控制器和action 方法。在開始實驗31之前,我們首先來解答上述問題,你可能會困惑為什么這個問題會放在最后來講,因為了解內部結構之前,需要更好的了解MVC。
理解RouteTable
在Asp.net mvc中有RouteTable這個概念,是用來存儲URL 路徑的,簡而言之,是保存已定義的應用程序的可能的URL pattern的集合。
默認情況下,路徑是項目模板組成的一部分。可在 Global.asax 文件中檢查到,在 Application_Start中會發現以下語句:
1: RouteConfig.RegisterRoutes(RouteTable.Routes);
App_Start文件夾下的 RouteConfig.cs文件,包含以下代碼塊:
1: namespace WebApplication1
2: {
3: public class RouteConfig
4: {
5: public static void RegisterRoutes(RouteCollection routes)
6: {
7: routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
8:
9: routes.MapRoute(
10: name: "Default",
11: url: "{controller}/{action}/{id}",
12: defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional }
13: );
14: }
15: }
16: }
RegisterRoutes方法已經包含了由routes.MapRoute 方法定義的默認的路徑。已定義的路徑會在請求周期中確定執行的是正確的控制器和action 方法。如果使用 route.MapRoute創建了多個路徑,那么內部路徑的定義就意味着創建Route對象。
MapRoute 方法也可與 RouteHandler 關聯。
理解ASP.NET MVC 請求周期
在本節中我們只講解請求周期中重要的知識點
1. UrlRoutingModule
當最終用戶發送請求時,會通過UrlRoutingModule 對象傳遞,UrlRoutingModule 是HTTP 模塊。
2. Routing
UrlRoutingModule 會從route table集合中獲取首次匹配的Route 對象,為了能夠匹配成功,請求URL會與route中定義的URL pattern 匹配。
當匹配的時候必須考慮以下規則:
- 數字參數的匹配(請求URL和URL pattern中的數字)
- URL pattern中的可選參數:
- 參數中定義的靜態參數
3. 創建MVC Route Handler
一旦Route 對象被選中,UrlRoutingModule會獲得 Route對象的 MvcRouteHandler對象。
4. 創建 RouteData 和 RequestContext
UrlRoutingModule使用Route對象創建RouteData,可用於創建RequestContext。RouteData封裝了路徑的信息如Controller名稱,action名稱以及route參數值。
Controller 名稱
為了從URL 中獲取Controller名稱,需要按規則執行如在URL pattern中{Controller}是標識Controller名稱的關鍵字。
Action Method 名稱
為了獲取action 方法名稱,{action}是標識action 方法的關鍵字。
Route 參數
URL pattern能夠獲得以下值:
1.{controller}
2.{action}
3. 字符串,如 “MyCompany/{controller}/{action}”,“MyCompany”是字符串。
4. 其他,如“{controller}/{action}/{id}”,”id“是路徑的參數。
例如:
Route pattern - > “{controller}/{action}/{id}”
請求 URL ->http://localhost:8870/BulkUpload/Upload/5
測試1
1: public class BulkUploadController : Controller
2: {
3: public ActionResult Upload (string id)
4: {
5: //value of id will be 5 -> string 5
6: ...
7: }
8: }
測試2
1: public class BulkUploadController : Controller
2: {
3: public ActionResult Upload (int id)
4: {
5: //value of id will be 5 -> int 5
6: ...
7: }
8: }
測試3
1: public class BulkUploadController : Controller
2: {
3: public ActionResult Upload (string MyId)
4: {
5: //value of MyId will be null
6: ...
7: }
8: }
5. 創建MVC Handler
MvcRouteHandler 會創建 MVCHandler的實例傳遞 RequestContext對象
6. 創建Controller實例
MVCHandler會根據 ControllerFactory的幫助創建Controller實例
7. 執行方法
MVCHandler調用Controller的執行方法,執行方法是由Controller的基類定義的。
8. 調用Action 方法
每個控制器都有與之關聯的 ControllerActionInvoker對象。在執行方法中ControllerActionInvoker對象調用正確的action 方法。
9. 運行結果
Action方法會接收到用戶輸入,並准備好響應數據,然后通過返回語句返回執行結果,返回類型可能是ViewResult或其他。
實驗31——實現對用戶有好的URL
1. 重新定義 RegisterRoutes 方法
在RegisterRoutes 方法中包含 additional route
1: public static void RegisterRoutes(RouteCollection routes)
2: {
3: routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
4:
5: routes.MapRoute(
6: name: "Upload",
7: url: "Employee/BulkUpload",
8: defaults: new { controller = "BulkUpload", action = "Index" }
9: );
10:
11: routes.MapRoute(
12: name: "Default",
13: url: "{controller}/{action}/{id}",
14: defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional }
15: );
16: }
2. 修改URL 引用
打開“~/Views/Employee”文件下的 AddNewLink.cshtml ,修改BulkUpload 鏈接,如下:
1:
2: <a href="/Employee/BulkUpload">BulkUpload</a>
3. 運行測試
關於實驗31
之前的URL 現在是否起作用?
是,仍然有用。BulkUploadController中的Index 方法可通過兩個URL 訪問。
1. ”http://localhost:8870/Employee/BulkUpload“
2. “http://localhost:8870/BulkUpload/Index”
Route 參數和Query 字符串有什么區別?
- Query 字符串本身是有大小限制的,而無法定義Route 參數的個數。
- 無法在Query 字符串值中添加限制,但是可以在Route 參數中添加限制。
- 可能會設置Route參數的默認值,而Query String不可能有默認值。
- Query 字符串可使URL 混亂,而Route參數可保持它有條理。
如何在Route 參數中使用限制?
可使用正則表達式。
如:
1: routes.MapRoute(
2: "MyRoute",
3: "Employee/{EmpId}",
4: new {controller=" Employee ", action="GetEmployeeById"},
5: new { EmpId = @"\d+" }
6: );
Action 方法:
1: public ActionResult GetEmployeeById(int EmpId)
2: {
3: ...
4: }
為了保證每個路徑參數都能獨立,因此參數名稱必須與Route Parameter一致。
是否需要將action 方法中的參數名稱與Route 參數名稱保持一致?
Route Pattern 也許會包含一個或多個RouteParameter,為了區分每個參數,必須保證action 方法的參數名稱與Route 參數名稱相同。
定義路徑的順序重要嗎?
有影響,在上面的實驗中,我們定義了兩個路徑,一個是自定義的,一個是默認的。默認的是最先定義的,自定義路徑是在之后定義的。
當用戶輸入“http://.../Employee/BulkUpload”地址后發送請求,UrlRoutingModule會搜索與請求URL 匹配的默認的route pattern ,它會將 Employee作為控制器的名稱,“BulkUpload”作為action 方法名稱。因此定義的順序是非常重要的,更常用的路徑應放在最后。
是否有什么簡便的方法來定義Action 方法的URL pattern?
我們可使用基於 routing 的屬性。
1. 基本的routing 屬性可用
在 RegisterRoutes 方法中在 IgnoreRoute語句后輸入代碼如下:
1: routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
2:
3: routes.MapMvcAttributeRoutes();
4:
5: routes.MapRoute(
6: ...
2. 定義action 方法的 route pattern
1: [Route("Employee/List")]
2: public ActionResult Index()
3: {
3. 運行測試
routing 屬性可定義route 參數,如下:
1: [Route("Employee/List/{id}")]
2: publicActionResult Index (string id) { ... }
IgnoreRoutes 的作用是什么?
當我們不想使用routing作為特別的擴展時,會使用IgnoreRoutes。作為MVC模板的一部分,在RegisterRoute 方法中下列語句是默認的:
1: routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
這就是說如果用戶發送以“.axd”為結束的請求,將不會有任何路徑加載的操作,請求將直接定位到物理資源。