前言
這一節我們開始講講基礎的東西也就是如題目所言,個人覺得當學習或者利用MVC時,必須得知道最新迭代版本新增了什么,至少得知道MVC 3、MVC 4或者MVC 5有什么區別,而不至於當利用到低版本時,出現某些特性就懵逼以至於認為是代碼出了問題,這一點是很明確需要我們去了解。
話題
在MVC 5之前都是基於約定的路由,如下:
routes.MapMvcAttributeRoutes(); routes.MapRoute( name: "Default", url: "{controller}/{action}/{id}", defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional } );
對應的控制器則是Home,方法則是Index。此時在該控制器以及方法是實際存在的,當我們有某種需求不想對應其真實的路由時,則不滿足我們的要求。所以在MVC 5和Web APi 2中則出現了一個新的特性名叫路由特性。通過我們定義的控制器和Action,此時我們利用路由特性則可以更靈活的去控制URL。請往下看。
MVC路由特性
控制器路由特性
此時我們添加此控制器路由特性,如果我們此時不需要對某一個Action執行特殊的映射,則此時將應用到該控制器下的所有Action。
[RoutePrefix("MyHome")] public class HomeController : Controller { public ActionResult Index() { return View(); } }
此時則對應如下:

我們還可以定義默認Action:如下:
[RoutePrefix("MyHome")] [Route("{action = index}")] public class HomeController : Controller { public ActionResult Index() { return View(); } }
很棒,出錯了,結果如下:

比較出乎意料,最終對默認的Action進行如下修改,刪除之間的空格則好使:
[Route("{action=index}")]
Action路由特性
通過在Action上定義一個特性使其應用到控制器上具體的Action方法。
public class HomeController : Controller { [Route("cnblogs/{id:int:min(1)}")] //訪問: cnblogs/1 public ActionResult Index(int id) { return View(); } [Route("cnblogs/about")] //訪問: cnblogs/about public ActionResult About() { ViewBag.Message = "Your application description page."; return View(); } public ActionResult Contact() //訪問: Home/Contact { ViewBag.Message = "Your contact page."; return View(); } }
區域路由特性
我們同樣可以使用路由區域特性來定義一個控制器屬於一個區域,我們知道來查找區域下的方法時通過區域注冊類來實現,若我們將一個區域中所有的控制器利用區域特性來實現,那么此時區域注冊類即 AreaRegistration 可以被移除掉。我們通過如下一個例子來看看。
[RouteArea("Admin")] [RoutePrefix("menu")] [Route("{action}")] public class MenuController : Controller { // 路由: /admin/menu/login public ActionResult Login() { return View(); } // 路由: /admin/menu/products [Route("products")] public ActionResult GetProducts() { return View(); } // 路由: /categories [Route("~/categories")] public ActionResult Categories() { return View(); } }
注意
(1)路由特性必須在基於約定的路由之前進行配置。
(2)當組合使用路由特性和基於約定路由時,此時未有使用路由特性時,則基於約定路由有效。
(3)當只有路由特性時,對於定義基於約定而沒有使用路由特性的Action方法時,此時將不會被訪問到。
使用路由特性的時機
基於約定的路由是比較復雜並且能夠支持一個確定的URI,但是我們可以通過使用路由特性來非常容易的定義URI模式。
例如有如下場景:在網上購物客戶下單時,根據客戶Id來下單,此時則有類似這樣的URI: client/clientId/orders ,此時這種情況我們很難利用基於約定的路由去進行控制,即使能使用基於約定的路由能夠做出來,但是會略顯復雜或者不能很量化的表現出我們描述的那樣。所以基於描述,我們利用路由特性就可以輕松的寫出,如下:
[Route("client/{clientId}/orders")] public IEnumerable<string> GetOrdersByClient(int clientId) { return Enumerable.Empty<string>(); }
啟動路由特性
上面說了那么多,即使如上述那樣使用了路由特性也不會有任何效果,因為在MVC 5中默認未啟動路由特性,我們需要在路由配置文件 RouteConfig 中的 RegisterRoutes 方法中進行如下注冊即可,so easy。
routes.MapMvcAttributeRoutes();
若只使用路由特性則可以在該方法中刪除如下基於約定的路由。
routes.MapRoute( name: "Default", url: "{controller}/{action}/{id}", defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional } );
MVC呈現母版頁
MVC中的模板想必大家再熟悉不過了,在建立MVC的默認項目中在 Views/Shared/ 文件夾下就有一個主默認母板頁面 _ViewStart 。這里我們需要討論的是呈現母版頁的不同方式。
那么問題來了,有可能出現這樣一個場景:當需要控制用戶訪問權限時,此時不同角色的用戶對應的母版頁頁面可能不同,此時我們應該如何去做呢?
方式一
我們可以在 _ViewStart 母版頁頁中進行如下修改來對應不同的母版頁,不同的角色對應不同的控制器,當授權於對應的控制器則呈現對應的母版頁,所以此時我們只需要得到該控制器即可。
@{ var controller = HttpContext.Current.Request.RequestContext.RouteData.Values["Controller"].ToString(); string layout = ""; if (controller == "Admin") { layout = "~/Views/Shared/_AdminLayout.cshtml"; } else { layout = "~/Views/Shared/_Layout.cshtml"; } Layout = layout; }
方式二
因為View方法有八個重載,最后一個重載的三個參數依次為視圖名稱,母版頁名稱,以及模型對象。所以此時可以我們直接通過ActionResult來呈現母版頁。
public ActionResult Index() { var model = new UserModel(); return View("Index", "_AdminLayout", model); }
方式三
最直接的則是在對應的頁面定義母版頁即可。
@{ Layout = "~/Views/Shared/_AdminLayout.cshtml"; }
總結
本節介紹了MVC 5中的路由特性以及呈現母版頁的幾種方式,文中若有不當之處或者未涉及之處,歡迎補充以及批評。我們下節見。
