理解預設路由表
當你建立一個新的ASP.NET MVC應用程式時,應用程式已經被配置為使用ASP.NET路由.ASP.NET路由在兩個地方設定。
第一點,在你的應用程式的Web設定檔(Web.config檔案檔案)中啟用ASP.NET路由在設定檔中有四個節點與路由有關:sytem.web.httpModules節,system.web.httpHandlers節,system.webserver.modules節,以及system.webserver.handlers節。特別要小心不要刪除了這些節點,因為沒有它們路由將不能工作。
第二點,也是更為重要的一點,在應用程式的Global.asax中檔案中建立了一個路由表.Global.asax檔案是一個特殊的檔案,它包含了作用於ASP.NET應用程式生命週期事件的事件處理常式。路由表在應用程式開始事件期間建立。
代碼清單1中的檔案包含了一個ASP.NET MVC應用程式的預設Global.asax檔案。
代碼清單1 - Global.asax.cs
使用系統; 使用 System.Collections.Generic; 使用 System.Linq; 使用 System.Web; 使用 System.Web.Mvc; 使用 System.Web.Routing; 命名空間 MvcApplication1{ //注意:有關啟用IIS6或IIS7傳統模式的說明, 請訪問http://go.microsoft.com/?LinkId=9394801 public class MvcApplication:System.Web.HttpApplication { public static void RegisterRoutes(RouteCollection路由) { routes.IgnoreRoute( “{resource} .axd / {* pathInfo}”); 路線。 MapRoute( “Default”, // Route name “{controller} / {action} / {id}”, //具有參數 的URL new {controller = “Home”,action =“Index”,id =“” } //參數預設值 ); } protected void Application_Start() { RegisterRoutes(RouteTable.Routes); } }} //具有參數的URL new {controller = “Home”,action =“Index”,id =“” } //參數defaults); } protected void Application_Start(){RegisterRoutes(RouteTable.Routes); }}} //具有參數的URL new {controller = “Home”,action =“Index”,id =“” } //參數defaults); } protected void Application_Start(){RegisterRoutes(RouteTable.Routes); }}} } protected void Application_Start(){RegisterRoutes(RouteTable.Routes); }}} } protected void Application_Start(){RegisterRoutes(RouteTable.Routes); }}}
當一個MVC應用程式首次運行時,會調用的Application_Start()方法。這個方法隨後調用了的RegisterRoutes()方法.RegisterRoutes()方法建立了路由表。
預設的路由表包含了一個路由(名叫預設).DEFAULT路由將URL的第一部分映射到控制器名,URL的第二部分映射到控制器動作,第三個部分映射到一個叫做ID的參數。
假設你在瀏覽器的地址欄輸入了下面的網址:
/首頁/索引/ 3
預設的路由將這個URL映射為下面的參數:
控制器=首頁
Action = Index
id = 3
當你請求URL /首頁/索引/ 3時,將會執行下面的代碼:
HomeController.Index(3)
預設路由包含了所有三個參數的預設值。如果你不提供控制器,那麼控制器參數預設值為首頁。如果你不提供動作,動作參數預設為值指標。最後,如果你不提供ID,ID參數預設為空白字串。
讓我們看看幾個例子,預設路由是如何將URL映射到控制器動作的設想你在瀏覽器地址欄輸入了下面的網址:
/家
由於預設路由參數的預設值,輸入這個網址將會調用代碼清單2中的HomeController的類的指數()方法。
代碼清單2 - HomeController.cs
使用 System.Web.Mvc; 命名空間 MvcApplication1.Controllers { [HandleError] public class HomeController:Controller { public ActionResult Index(string id) { return View(); } } }
在代碼清單2中,HomeController類包含了一個叫做Index()的方法,它接受一個叫做Id的參數.URL / Home將會導致調用Index()方法,並使Null 字元串作為Id參數的值。
出於MVC架構調用控制器動作的方式,URL / Home也符合代碼清單3中HomeController類的索引()方法。
代碼清單3 - HomeController.cs(不含參數的索引動作)
使用 System.Web.Mvc; 命名空間 MvcApplication1.Controllers { [HandleError] public class HomeController:Controller { public ActionResult Index() { return View(); } } }
代碼清單3中的Index()方法不接受任何的參數.URL / Home將會導致調用這個Index()方法.URL / Home / Index / 3也會調用這個方法(Id被忽略)。
URL / Home也會符合代碼清單4中HomeController類的索引()方法。
代碼清單4 - HomeController.cs(使用可空參數的索引動作)
使用 System.Web.Mvc; 命名空間 MvcApplication1.Controllers { [HandleError] public class HomeController:Controller { public ActionResult Index(int?id) { return View(); } } }
在代碼清單4中,索引()方法擁有一個整數參數。因為這個參數是一個可空參數(可以擁有空值),因此可以調用指數()而不會引發錯誤。
最後,使用URL / Home調用代碼清單5中的Index()方法將會引發一個異常,因為Id參數並非一個可空參數。如果你試圖調用Index()方法,那麼你將會獲得一個圖1中所示的錯誤。
代碼清單5 - HomeController.cs(含有Id參數的索引動作)
使用 System.Web.Mvc; 命名空間 MvcApplication1.Controllers { [HandleError] public class HomeController:Controller { public ActionResult Index(int id) { return View(); } } }
圖01:調用一個期望參數值的控制器動作
另一方面,URL / Home / Index / 3能夠與代碼清單5中的索引控制器動作很好地工作./Home/Index/3請求將會引發調用含有一個Id的索引()方法,且該Id值為3。
這篇教程的目的是為你提供一個ASP.NET路由的簡短介紹。我們仔細查看了預設的路由表,它在你建立新的ASP.NET MVC應用程式時獲得。你學習了預設的路由表如何將URL映射到控制器動作。
2.建立自訂路由
在這篇教程中,你會學習到如何為ASP.NET MVC應用程式添加自訂路由。你會學習如何將Global.asax檔案中的預設路由表修改為自訂路由。
對於簡單的ASP.NET MVC應用程式,預設的路由表已經可以很好的完成工作了。然而,你可以發現會存在特定的路由需求在這種情況下,你可以建立一個自訂路由。
設想一下,舉個例子,你正在建立一個部落格應用程式你可能想要像這樣處理即將到來的請求:
/存檔/ 2009年12月25日
當使用者輸入這一請求,你想要返回對應於日期2009年12月25日的部落格條目。為了處理這種類型的請求,你需要建立一個自訂路由。
代碼清單1中的Global.asax包含了一個新的自訂路由,命名為了部落格,它處理了類似/存檔/條目日期這樣的請求。
代碼清單1 - Global.asax(含有自訂路由)
使用 System.Web.Mvc; 使用 System.Web.Routing; 命名空間 MvcApplication1 { public class MvcApplication:System.Web.HttpApplication { public static void RegisterRoutes(RouteCollection routes) { routes.IgnoreRoute(“{resource} .axd / {* pathInfo}”); routes.MapRoute( “Blog”, //路由名稱 “Archive / {entryDate}”, //具有參數 的URL new {controller = “Archive”,action =“ } //參數defaults ); routes.MapRoute( “Default”,//路由名稱 “{controller} / {action} / {id}”,//具有參數 的URL new {controller = “Home”,action =“Index”,id =“” } //參數defaults ); } protected void Application_Start() { RegisterRoutes(RouteTable.Routes); } } } } //參數defaults); routes.MapRoute(“Default”,//路由名稱“{controller} / {action} / {id}”,//具有參數的URL new {controller = “Home”,action =“Index”,id =“” } //參數defaults); } protected void Application_Start(){ RegisterRoutes(RouteTable.Routes); } } } ,//路由名稱“{controller} / {action} / {id}”,//具有參數的URL new {controller = “Home”,action =“Index”,id =“” } //參數defaults); } protected void Application_Start(){ RegisterRoutes(RouteTable.Routes); } } } , //路由名稱“{controller} / {action} / {id}”, //具有參數的URL new {controller = “Home”,action =“Index”,id =“” } //參數defaults); } protected void Application_Start(){ RegisterRoutes(RouteTable.Routes); } } } //具有參數的URL new {controller = “Home”,action =“Index”,id =“” } //參數defaults); } protected void Application_Start(){ RegisterRoutes(RouteTable.Routes); } } } //具有參數的URL new {controller = “Home”,action =“Index”,id =“” } //參數defaults); } protected void Application_Start(){ RegisterRoutes(RouteTable.Routes); } } }
添加到路由表中的路由順序非常重要。我們的新自訂部落格路由在現有的預設路由前面。如果你將這個順序顛倒過來,那麼預設路由將總是被調用,而不是自訂路由。
自訂部落格路由匹配任何以/存檔/作為開始的請求因此,它匹配所有下面的網址:
/存檔/ 2009年12月25日
/存檔/ 2004年10月6日
/存檔/蘋果
自訂路由將即將到來的請求映射到名為存檔的控制器,並且調用了條目()動作。當調用項()方法時,條目日期作為entryDate參數進行了傳遞。
代碼清單2 - ArchiveController.cs
使用系統; 使用 System.Web.Mvc; 命名空間 MvcApplication1.Controllers{ public class ArchiveController:Controller { public string Entry(DateTime entryDate) { return “您從” + entryDate.ToString())請求了條目。 } }}
注意到代碼清單2中的條目()方法接受一個日期時間類型的參數.MVC架構非常的聰明,足以自動地將URL中的條目日期轉換為日期時間值。如果URL中的條目日期參數不能轉換為日期時間,將會引發錯誤(1)。
圖1 - 轉換參數時的錯誤
這篇教程的目的是示範如何建立自訂路由。你學習了如何在Global.asax中檔案的路由表中添加自訂路由,該路由代表著部落格條目。我們討論了如何將對部落格條目的請求映射到名為ArchiveController的控制器,和名為項()的控制器動作上。
3.建立路由約束
你可以使用路由約束來限制匹配特定路由的瀏覽器請求。可以使用Regex來指定一個路由約束。
舉個例子,假設你已經在Global.asax中檔案中定義了一個路由。
代碼清單1 - Global.asax.cs
routes.MapRoute( “Product”, “Product / {productId}”, new {controller =“Product”,action =“Details”} );
代碼清單1包含一個叫做產品的路由。你可以使用產品路由將瀏覽器請求映射到代碼清單2中的ProductController的。
代碼清單2 - Controllers \ ProductController.cs
使用 System.Web.Mvc; 命名空間 MvcApplication1.Controllers { public class ProductController:Controller { public ActionResult Details(int productId) { return View(); } } }
注意到產品控制器公布的詳細資料()動作接受一個叫做的productId的參數。這個參數是一個整數參數。
定義在代碼清單1中的路由將會匹配下面的任意網址:
/產品/ 23/產品/ 7不幸的是,路由也會匹配下面的網址:/產品/嗒嗒/產品/蘋果
因為詳細()動作期望的是一個整數值,發起一個含有非整數值的請求將會導致錯誤。舉個例子,如果你在瀏覽器中輸入/產品/蘋果網址,那麼你將會得到圖1所示的錯誤頁。
圖1:錯誤頁
你實際想做的是只匹配包含合適整數productId參數的URL。當定義路由來限制與路由相匹配的網址時,你可以使用約束。代碼3中的修改後的產品路由包含了一個Regex,它限制了只匹配數字。
代碼清單3 - Global.asax.cs
routes.MapRoute( “Product”, “Product / {productId}”, new {controller =“Product”,action =“Details”}, new {productId = @“\ d +”} )
Regex\ D +匹配一個或多個整數這個限制使得產品路由匹配了下面的網址:
/產品/ 3/產品/ 8999但是不匹配下面的網址:/產品/蘋果/產品
這些瀏覽器請求將自由另外的路由處理,或者,如果沒有匹配的路由,將會返回一個“資源找不到”錯誤。
建立一個自訂路由約束
這篇教程的目標是示範如何建立一個自訂路由約束。自訂路由約束允許你阻止某個路徑被匹配,除非滿足一些自訂的條件。
在這篇教程中,我們建立了一個本地主機路由約束.Localhost路由約束只匹配本機電腦發出的請求。通過互連網發出的遠程請求不會被匹配。
。你可以通過實現IRouteConstraint介面來實現一個自訂路由這是一個極其簡單的介面,它只描述了一個方法:
bool Match( HttpContextBase httpContext, Route route, string parameterName, RouteValueDictionary值, RouteDirection routeDirection )
這個方法返回一個布爾值。如果返回了假,與約束相關聯的路由將不會匹配瀏覽器請求。
本地主機約束包含在了代碼清單1中。
代碼清單1 - LocalhostConstraint.cs
使用 System.Web; 使用 System.Web.Routing; 命名空間 MvcApplication1.Constraints { public class LocalhostConstraint:IRouteConstraint { public bool Match ( HttpContextBase httpContext, Route route, string parameterName, RouteValueDictionary values, RouteDirection routeDirection ) { return httpContext.Request.IsLocal; } } }
代碼清單1中的約束利用了HttpRequest的類公布的IsLocal屬性。當發出請求的IP地址是127.0.0.1或者與伺服器的IP地址相同時,這個屬性返回真。
你在定義於Global.asax中的路由中使用了自訂約束。代碼清單2中的Global.asax中檔案使用了本地主機約束來阻止任何人要求管理員頁面,除非他們從本機伺服器發出請求。舉個例子,當請求來自遠程伺服器時,對於/管理/ DeleteAll的請求將會失敗。
代碼清單2 - Global.asax
使用系統; 使用 System.Collections.Generic; 使用 System.Linq; 使用 System.Web; 使用 System.Web.Mvc; 使用 System.Web.Routing; 使用 MvcApplication1.Constraints; 命名空間 MvcApplication1{ public class MvcApplication:System.Web.HttpApplication { public static void RegisterRoutes(RouteCollection routes){ routes.IgnoreRoute( “{resource} .axd / {* pathInfo}”); routes.MapRoute( “Admin”, “Admin / {action}”, isLocal = new LocalhostConstraint()} ); //routes.MapRoute( // “預設”,//路線名稱 // “{控制器} / {行動} /(編號)”,// URL與參數 // 新 {控制器= “首頁”,動作=“索引“,id =”“ } //參數defaults //); } protected void Application_Start(){ RegisterRoutes(RouteTable.Routes); } } }
本地主機約束使用在了管理路由的定義中這個路由不會被遠程瀏覽器請求所匹配然而,應該意識到定義在Global.asax中中的其他路由可能會匹配相同的請求理解這一點很重要。:約束阻止了特定路由匹配某一請求,而不是所有定義在Global.asax中檔案中的路由。
注意到預設路由在代碼清單2中的Glabal.asax檔案中被注釋掉了。如果你包含預設路由,那麼預設路由將會匹配對管理控制器的請求。在這種情況下,遠端使用者仍然可以調用管理控制器的動作,即使他們的請求不匹配管理路由。
【相關推薦】
1. 什麼是ASP.NET MVC ?總結ASP.NET MVC
2. 詳細介紹ASP.NET MVC--控制器(controller)
3. 詳細介紹ASP.NET MVC--視圖
4. 深入瞭解ASP.NET MVC與WebForm的區別
5. 通過asp.net mvc開發自訂菜單編輯工具的程式碼範例