一.URL 生成
接著上篇講MVC的路由,MVC 應(yīng)用程序可以使用路由的 URL 生成功能,生成指向操作的 URL 鏈接。 生成 URL 可消除硬編碼 URL,使代碼更穩(wěn)定、更易維護(hù)。 此部分重點介紹 MVC 提供的 URL 生成功能,并且僅涵蓋 URL 生成工作原理的基礎(chǔ)知識。 IUrlHelper 接口用于生成 URL,是 MVC 與路由之間的基礎(chǔ)結(jié)構(gòu)的基礎(chǔ)部分。 在控制器、視圖和視圖組件中,可通過 Url 屬性找到 IUrlHelper 的實例。
//
// mvc 框架的ControllerBase類下
//摘要:
// Gets or sets the Microsoft.AspNetCore.Mvc.IUrlHelper.
public IUrlHelper Url { get; set; }
1.1 傳統(tǒng)路由下的url生成
下面示例中,通過使用IUrlHelper接口在index頁面生成指向另一操作Destination的 URL超連接。
[Route("Home/Index")]
public IActionResult Index()
{
// Generates /Home/Destination
var url = Url.Action("Destination");
var urlAddress = "<a href=\"" + url + "\" >Click on to the Destination</a>";
ViewData["url"] = urlAddress;
return View();
}
public IActionResult Destination()
{
return View();
}
// Index.cshtml
@Html.Raw(ViewData["url"].ToString())
當(dāng)加載index頁面后,點擊超連接"Click on to the Destination" 將進(jìn)入后臺控制器的Destination操作中。
上面的 Url.Action 示例假定使用傳統(tǒng)路由,但 URL 生成功能的工作方式與屬性路由相似,只不過概念不同。 在傳統(tǒng)路由中,路由值用于擴(kuò)展模板。controller 和 action 的路由值通常出現(xiàn)在該模板中, 這種做法可行是因為通過路由匹配的 URL 遵守某項約定。 這里的擴(kuò)展模板指的是routes.MapRoute來添加路由規(guī)則約定。
1.2 屬性路由下的url生成
在屬性路由中,controller 和 action 的路由值不能出現(xiàn)在模板中(也就是不會使用routes.MapRoute),它們用于查找要使用的模板。
//首先不用傳統(tǒng)路由,去掉了routes.MapRoute
public void Configure(IApplicationBuilder app)
{
app.UseMvc();
}
[Route("")]
public IActionResult Index()
{
// Generates /custom/url/to/destination
var url = Url.Action("Destination");
var urlAddress = "<a href=\"" + url + "\" >"+url+"</a>";
ViewData["url"] = urlAddress;
return View();
}
[HttpGet("custom/url/to/destination")]
public IActionResult Destination()
{
return View();
}
生成如下圖所示 :所以會生成與httpget配置的路徑一樣,是因為屬性路由下的url生成,它們用于查找要使用的模板。MVC 生成一個包含所有屬性路由操作的查找表,并匹配 controller 和 action 的值,以選擇要用于生成 URL 的路由模板

1.3 根據(jù)action名稱生成 URL
Url.Action (IUrlHelper . Action) 以及所有相關(guān)重載都基于這樣一種想法:用戶想通過指定控制器名稱和操作名稱來指定要鏈接的內(nèi)容。
[Route("")]
public IActionResult Index()
{
// Generates /Home/Destination/1?color=red
var url = Url.Action("Destination","Home",new { id=1 , color="red"});
var urlAddress = "<a href=\"" + url + "\" >" + url + "</a>";
ViewData["url"] = urlAddress;
return View();
}
public IActionResult Destination(int id,string color)
{
return View();
}

1.4 根據(jù)路由名稱生成 URL
IUrlHelper 還提供 Url.RouteUrl 系列的方法。 這些方法類似于 Url.Action。Url.RouteUrl 指定一個路由名稱,以使用特定路由來生成 URL,通常不指定控制器或操作名稱。
[Route("")]
public IActionResult Index()
{
// Generates /custom/url/to/destination
var url = Url.RouteUrl("Destination_Route");
var urlAddress = "<a href=\"" + url + "\" >Click on to the Destination</a>";
ViewData["url"] = urlAddress;
return View();
}
[HttpGet("custom/url/to/destination", Name = "Destination_Route")]
public IActionResult Destination()
{
return View();
}

1.5 其它生成
(1)在 HTML 中生成 URL: IHtmlHelper 提供 HtmlHelper 方法 Html.BeginForm 和 Html.ActionLink,可分別生成 <form> 和 <a>元素。 這些方法使用 Url.Action 方法來生成 URL,并且采用相似的參數(shù)。
(2)在action中重定向:RedirectToAction("Index");
二. area區(qū)域路由
區(qū)域是一種 MVC 功能,用于將相關(guān)功能整理到一個組中,作為單獨的路由命名空間(用于控制器操作)和文件夾結(jié)構(gòu)(用于視圖)。 通過使用區(qū)域,應(yīng)用程序可以有多個名稱相同的控制器,只要它們具有不同的區(qū)域。 通過向 controller 和 action 添加另一個路由參數(shù) area,可使用區(qū)域為路由創(chuàng)建層次結(jié)構(gòu)。
下面是mvc文件結(jié)構(gòu),對于users控制器,在視圖層多了一級Manage文件夾。如何使users控制器中AddUser操作關(guān)聯(lián)AddUser.cshtml呢,下面使用區(qū)域路由來實現(xiàn):

app.UseMvc(routes =>
{
//用于名為 Blog 的區(qū)域
routes.MapAreaRoute("blog_route", "Blog","Manage/{controller}/{action}/{id?}");
/*
* 注釋的MapRoute與上面的區(qū)域路由作用一樣
routes.MapRoute("blog_route", "Manage/{controller}/{action}/{id?}",
defaults: new { area = "Blog" }, constraints: new { area = "Blog" });
*/
routes.MapRoute(
name: "default",
template: "{controller=Home}/{action=Index}/{id?}");
});
//控制器上應(yīng)用區(qū)域路由
[Area("Blog")]
public class UsersController : Controller
{
// GET: /<controller>/
public IActionResult AddUser()
{
return View();
}
}
在瀏覽器中輸入/Manage/Users/AddUser 將自動進(jìn)入AddUser()中,這是因為當(dāng)前路由:Manage/{controller}/{action}/{id?}符合blog模板,所以使用Blog區(qū)域路由。
三. IActionConstraint 路由約束
實現(xiàn)IActionConstraint最簡單的方法是創(chuàng)建派生自 System.Attribute 的類,并將其置于操作和控制器上。MVC 將自動發(fā)現(xiàn)任何應(yīng)用屬性IActionConstraint的操作和控制器。
在下面的示例中,約束基于路由數(shù)據(jù)中的國家/地區(qū)代碼選擇操作,開發(fā)人員負(fù)責(zé)實現(xiàn)Accept 方法,當(dāng)路由中id值為en-US時Accept 方法返回 true 以表示該操作是匹配項,一切按正常解析返回客戶端。 如果Accept 方法返回false將不執(zhí)行IActionConstraint標(biāo)記的action,向客戶端返回404錯誤。
//定義ActionConstraint屬性約束
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)
{
return string.Equals(
context.RouteContext.RouteData.Values["id"].ToString(),
_countryCode,
StringComparison.OrdinalIgnoreCase);
}
}
//應(yīng)用路由的action約束,并且路由中id值為en-US
[CountrySpecific("en-US")]
public IActionResult Privacy(string countryCode)
{
return View();
}
在瀏覽器測試時:如果輸入http://localhost:30081/home/Privacy/zh-cn,則網(wǎng)頁顯示404。如果輸入http://localhost:30081/home/Privacy/en-US 則符合約束,網(wǎng)頁顯示正常。
參考文獻(xiàn)
官方資料:asp.net core routing