(9)ASP.NET Core 中的MVC路由(二)
1.URL生成
MVC應用程式可以使用路由的URL生成功能,生成指向操作(Action)的URL連結。 IUrlHelper 介面用於生成URL,是MVC與路由之間的基礎部分。在控制器、檢視和檢視元件中,可通過Url屬性找到IUrlHelper的例項。在此示例中,將通過Controller.Url屬性使用IUrlHelper介面來生成指向另一項操作的URL。
public class HomeController : Controller { public IActionResult Index() { var url1= Url.Action("Privacy");//Url:Home/Privacy var url2 = Url.Action("Error");//Url:Home/Error var url3 = Url.Action("Article");//Url:Blog/Article var msg = $"url1: {url1}"; msg += $"\r\nurl2: {url2}"; msg += $"\r\nurl3: {url3}"; return Content(msg); } [HttpGet("custom/url/to/privacy")]//定義一個路由模版 public IActionResult Privacy() { return View(); } public IActionResult Error(string code) { return View(new ErrorViewModel { RequestId = Activity.Current?.Id ?? HttpContext.TraceIdentifier }); } }
響應結果:
如果Url.Action方法都只設置Action名稱,那麼IUrlHelper介面會獲取通過指向當前所在控制器裡存在的Action操作,然後生成URL。如果當前控制器裡Action操作自定義路由模版,則會生成對應路由模版URL。如果Action不存在當前控制器裡,則會生成空字串的URL。
2.URL生成方式
2.1根據操作名稱生成URL
Url.Action (IUrlHelper. Action) 可以通過指定控制器(Controller)名稱和操作(Action)名稱來生成要連結的內容。而過載方法裡還包含新增路由值物件,比如Url.Action("Home", "Index", new { id = 17 }),此處路由值物件就是new { id = 17 }(路由值物件通常是匿名型別的物件)。下面我們通過示例來看看:
public class HomeController : Controller { public IActionResult Index(int id) { var url = Url.Action("Index", "Home", new { id = 17, color = "red", sex = "m" }); return View(); } }
通過DEBUG檢視生成URL:
2.2根據路由生成URL
上面的程式碼演示瞭如何通過傳入控制器和操作名稱來生成URL。IUrlHelper還提供 Url.RouteUrl系列的方法。這些方法類似於Url.Action,但它們不會將action和controller的當前值複製到路由值。最常見的用法是指定一個路由名稱,以使用特定路由來生成URL,通常不指定控制器或操作名稱。
public class HomeController : Controller { public IActionResult Index(int id) { var url = Url.RouteUrl("Privacy_Name"); return View(); } [HttpGet("custom/url/to/privacy",Name = "Privacy_Name")]//定義一個路由模版 public IActionResult Privacy() { return View(); } }
通過DEBUG檢視生成URL:
2.3在HTML中生成URL
IHtmlHelper提供HtmlHelper方法Html.BeginForm和Html.ActionLink,可分別生成<form>和 <a>元素。這些方法使用Url.Action方法來生成URL,並且採用相似的引數。HtmlHelper的配套Url.RouteUrl為Html.BeginRouteForm和Html.RouteLink,兩者具有相似的功能。
@using (Html.BeginForm("Article", "Blog", FormMethod.Get, new { name = "nForm", id = "idForm" })){} @Html.ActionLink("Article", "Article", "Blog")
通過瀏覽器工具檢視生成HTML:
2.4在操作結果中生成URL
以上示例展示瞭如何在控制器中使用IUrlHelper。不過,控制器中最常見的用法是將URL生成為操作結果的一部分。ControllerBase和Controller基類為操作結果提供簡便的方法來引用另一項操作。一種典型用法是在接受使用者輸入後進行重定向。
public IActionResult Edit(int id, Customer customer) { if (ModelState.IsValid) { // Update DB with new details. return RedirectToAction("Index"); } return View(customer); }
3.區域(Area)
區域是ASP.NET功能,它提供了一種將ASP.NET Core Web應用程式劃分為更小的功能組的方法,每個功能組都有自己的一組Razor Pages、控制器(Controllers)、檢視(Views)和模型(Models)。區域實際上是應用程式內的結構。在ASP.NET Core Web專案中,Pages、模型、控制器和檢視等邏輯元件儲存在不同的資料夾中。ASP.NET Core執行時使用命名約定來建立這些元件之間的關係。對於大型應用程式,將應用程式區分為獨立的高階功能區域可能更有利。例如,具有多個業務單位(如結賬、計費、搜尋等)的電子商務應用程式。每個單位都有自己的區域,以包含檢視、控制器、Razor Pages和模型。下面的示例我們根據採購(Purchase)和銷售(Sale)訂單兩個業務場景在MVC中配置使用預設傳統路由和區域路由:
public class Startup { public void Configure(IApplicationBuilder app) { app.UseMvc(routes => { routes.MapAreaRoute( name: "MyAreaPurchase", areaName: "Purchase", template: "Purchase/{controller}/{action}/{id?}"); routes.MapAreaRoute( name: "MyAreaSale", areaName: "Sale", template: "Sale/{controller}/{action}/{id?}"); routes.MapRoute( name: "default", template: "{controller=Home}/{action=Index}/{id?}"); //等價於 //routes.MapAreaRoute("purOrder_route", "Purchase", //"Purchase/{controller}/{action}/{id?}"); //routes.MapAreaRoute("saleOrder_route", "Sale", //"Sale/{controller}/{action}/{id?}"); //routes.MapRoute("default", "{controller=Home}/{action=Index}/{id?}"); }); } }
在上面的示例中,路由值將與以下操作匹配:
[Area("Purchase")] public class PurOrderController : Controller { public IActionResult Index() { return View(); } } [Area("Sale")] public class SaleOrderController : Controller { public IActionResult Index() { return View(); } }
在每個控制器加入AreaAttribute屬性是表示該控制器是某個區域的一部分,比方說,PurOrderController控制器位於Purchase區域中,SaleOrderController控制器位於Sale區域中。 而沒有 [Area] 屬性的控制器不是任何區域的成員,在路由提供area路由值時不匹配時,開啟對應控制器下的檢視時將無法開啟。在上面的示例中,只有所列出PurOrderController、SaleOrderController控制器下檢視Index的路由值 { area = Purchase, controller = PurOrder, action = Index } 、{ area = Sale, controller = SaleOrder, action = Index }匹配才能開啟對應連結。
4.實現IActionConstraint的路由約束
實現IActionConstraint約束最簡單的方法是建立派生自System.Attribute的類,並將其置於操作(Action)和控制器(Controller)上。 MVC將自動發現任何應用為屬性的IActionConstraint屬性,便對應用程式模型應用程式進行約束。在下面的示例中,對路由資料中的國家/地區選擇操作進行約束。
public class CountrySpecificAttribute : Attribute, IActionConstraint { private readonly string _countryCode; public CountrySpecificAttribute(string countryCode) { _countryCode = countryCode; } public int Order { get { return 0; } } public bool Accept(ActionConstraintContext context) { string routeDataValue = context.RouteContext.RouteData.Values["id"] == null ? "" : context.RouteContext.RouteData.Values["id"].ToString(); return string.Equals( routeDataValue, _countryCode, StringComparison.OrdinalIgnoreCase); } } public class HomeController : Controller { [CountrySpecific("en-us")] public IActionResult Index(string id) { return View(); } }
根據官網解釋IActionConstraint.Order是順序約束意思,比如HomeController 控制器上有[CountrySpecific("en-us")]和[HttpGet](或者其他自定義屬性約束)屬性約束,數值較低的屬性約束先執行。響應結果通過下面表格進行分析:
Route Url |
Result |
[SERVICE_NAME]/Home/Index/en-us |
200 |
[SERVICE_NAME]/Home/Index/zh-cn |
404 |
通過以上的表格可以知道,在此例中,當Index傳入路由值(en-us)匹配時,Accept方法返回true以表示該操作是匹配項,然後可以開啟連線,反之傳入值(zh-cn)不匹配,則404。
參考文獻:
在 ASP.NET Core 中路由到控制器