一. URL 生成
接着上篇讲 MVC 的路由, MVC 应用程序可以使用路由的 URL 生成功能, 生成指向操作的 URL 链接. 生成 URL 可消除硬编码 URL, 使代码更稳定, 更易维护. 此部分重点介绍 MVC 提供的 URL 生成功能, 并且仅涵盖 URL 生成工作原理的基础知识. IUrlHelper 接口用于生成 URL, 是 MVC 与路由之间的基础结构的基础部分. 在控制器, 视图和视图组件中, 可通过 Url 属性找到 IUrlHelper 的实例.
- //
- // mvc 框架的 ControllerBase 类下
- // 摘要:
- // Gets or sets the Microsoft.AspNetCore.Mvc.IUrlHelper.
- public IUrlHelper Url { get; set; }
1.1 传统路由下的 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())
当加载 index 页面后, 点击超连接 "Click on to the Destination" 将进入后台控制器的 Destination 操作中.
上面的 Url.Action 示例假定使用传统路由, 但 URL 生成功能的工作方式与属性路由相似, 只不过概念不同. 在传统路由中, 路由值用于扩展模板. controller 和 action 的路由值通常出现在该模板中, 这种做法可行是因为通过路由匹配的 URL 遵守某项约定. 这里的扩展模板指的是 routes.MapRoute 来添加路由规则约定.
1.2 属性路由下的 url 生成
在属性路由中, controller 和 action 的路由值不能出现在模板中(也就是不会使用 routes.MapRoute), 它们用于查找要使用的模板.
- // 首先不用传统路由, 去掉了 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 根据 action 名称生成 URL
Url.Action (IUrlHelper . Action) 以及所有相关重载都基于这样一种想法: 用户想通过指定控制器名称和操作名称来指定要链接的内容.
- [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 根据路由名称生成 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, 并且采用相似的参数.
(2)在 action 中重定向: RedirectToAction("Index");
二. area 区域路由
区域是一种 MVC 功能, 用于将相关功能整理到一个组中, 作为单独的路由命名空间 (用于控制器操作) 和文件夹结构(用于视图). 通过使用区域, 应用程序可以有多个名称相同的控制器, 只要它们具有不同的区域. 通过向 controller 和 action 添加另一个路由参数 area, 可使用区域为路由创建层次结构.
下面是 mvc 文件结构, 对于 users 控制器, 在视图层多了一级 Manage 文件夹. 如何使 users 控制器中 AddUser 操作关联 AddUser.cshtml 呢, 下面使用区域路由来实现:
- App.UseMvc(routes =>
- {
- // 用于名为 Blog 的区域
- routes.MapAreaRoute("blog_route", "Blog","Manage/{controller}/{action}/{id?}");
- /*
- * 注释的 MapRoute 与上面的区域路由作用一样
- 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?}");
- });
- // 控制器上应用区域路由
- [Area("Blog")]
- public class UsersController : Controller
- {
- // GET: /<controller>/
- public IActionResult AddUser()
- {
- return View();
- }
- }
在浏览器中输入 / Manage/Users/AddUser 将自动进入 AddUser()中, 这是因为当前路由: Manage/{controller}/{action}/{id?}符合 blog 模板, 所以使用 Blog 区域路由.
三. IActionConstraint 路由约束
实现 IActionConstraint 最简单的方法是创建派生自 System.Attribute 的类, 并将其置于操作和控制器上. MVC 将自动发现任何应用属性 IActionConstraint 的操作和控制器.
在下面的示例中, 约束基于路由数据中的国家 / 地区代码选择操作, 开发人员负责实现 Accept 方法, 当路由中 id 值为 en-US 时 Accept 方法返回 true 以表示该操作是匹配项, 一切按正常解析返回客户端. 如果 Accept 方法返回 false 将不执行 IActionConstraint 标记的 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);
- }
- }
- // 应用路由的 action 约束, 并且路由中 id 值为 en-US
- [CountrySpecific("en-US")]
- public IActionResult Privacy(string countryCode)
- {
- return View();
- }
在浏览器测试时: 如果输入 http://localhost:30081/home/Privacy/zh-cn, 则网页显示 404. 如果输入 http://localhost:30081/home/Privacy/en-US 则符合约束, 网页显示正常.
参考文献
官方资料: ASP.NET core routing
来源: https://www.cnblogs.com/MrHSR/p/10250668.html