上一篇中老周给伙伴们介绍了自定义视图搜索路径的方法, 本篇咱们扯一下有关 URL 路径规则的名称问题在扯今天的话题之前, 先补充点东东在上一篇中设置视图搜索路径时用到三个有序参数:{2}{1}{0}, 分别是 AreaControllerAction 其中说到几个特殊的视图, 如_Layout.cshtml_ViewStart.cshtml 等_Layout.cshtml 页默认放在 /Views/Shared 目录下, 但,_ViewStart.cshtml 和 _ViewImports.cshtml 这两个不应该放在 Shared 目录下, 一般应放到 /Views 下, 这样它们可以作用于所有的视图如果放到了 Shared 目录下, 它们只对 Shared 目录中的视图起作用, 而对于 Views 下的其他视图不起作用
比如, 放到 /Views 下
Views(目录)
- _ViewImports.cshtml
- _ViewStart.cshtml
Home(目录, Controller 的名字)
Index.cshtml(视图, Action)
其中, Home 是子目录, 对应着控制器 Home,Home 中的 Index.cshtml 视图对应着 Action 名 Index 此时,_ViewStart 和 _ViewImports 中的内容会应用到 /Views 下的所有视图中(如 Index.cshtml)
要是改为这样
- Views
- Home
- About.cshtml
- Index.cshtml
- _ViewImports.cshtml
- _ViewStart.cshtml
- Users
- AddNew.cshtml
此时, Views 有两个子目录, Home 是一个控制器, Users 是另一个控制器, 这时候,_ViewStart 和 _ViewImports 只对 Home 下面的视图起作用, 对 Users 目录下的视图是不起作用的
_ViewStart 主要用途是在所有视图文件执行之前执行, 一般我们用它来设置 Layout 属性, 以指定使用的布局页(相当于页面母板), 这样一来, 我们不需要在每个视图上都加 Layout = "xxxx" 了_ViewImports 主要是用来引入要用到的命名空间(就是 C# 中的 using), 这样你不需要在每个视图中写一堆 @using Razor 标记了
这两个文件都是约定式的, 所以你不应该随便改它的名字,_ViewImports 可以通过 RazorTemplateEngineOptions 类的 ImportsFileName 属性来修改, 不过,_ViewStart 好像不能改, 老周看到 asp.net core 源码中是写死了的, 估计是不能改文件名的
其实, 这两个文件不应该改名, 而且你改了名字也没啥用, 反正功能是不变的, 还是遵守约定好一些, 这样人家看你的项目时也看得懂_Layout.cshtml 文件如非必要, 也不应该改名字, 如果你的应用要用多个布局视图, 可能建个子目录, 然后每个子目录下放_Layout, 这样结构清晰一些, 毕竟, 看到 _Layout.cshtml 就明白它是母板页了
规则模板
我们都知道, 在 Startup.Configure 方法中, 会以此方式来指定 URL 路径规则
- app.UseMvc(route =>
- {
- route.MapRoute("main", "{controller=Students}/{action=List}/{sid?}");
- route.MapRoute("edit_post", "{controller}-{action}");
- });
你可以添加 K 条规则, 比如上面的例子, 我添加了两条规则
{controller} 和 {action} 是约定的名称, 用来识别 Controller 和 Action , 所以你不要自作聪明乱来, 必要有些写死了的参数才能进行 URL 分析, 不然, 你给个 URL http://dog.org/shopping/pay/500, 那应用程序根本不知道哪一段是表示 Controller, 哪一段是表示 action
如果确定了 controller 和 action 这两个值, 那么其他的参数就好分析了
其他参数如果是可选的, 可以在后面加个问号, 比如 {controller}/{action}/{id?}, 这表示 id 的值是可选的
上面老周添加的两个规则中, edit_post 那个其实不太规范, URL 中各段最好用 / 来分隔, 因为 - 有时候是不允许用的, 比如, id 参数前面就不能用, 你不能写成 {controller}-{action}-{id?}, 要是 id 中包含了字符 -, 咋办呢? 而 / 则不同, URL Encode 后不会冒出这个字符来
所以用 / 最好, 这里用 - 只是老周故意用来演示而已, URL 嘛, 没必要玩花样, 没意义
基于 Attribute 指定的 URL 路由
在 Startup.Configure 方法中指定的 URL 路由是作用于整个应用程序的, 如果想为个别控制器或个别 Action 指定路由规则, 那么可以考虑使用 Attribute 的形式
attribute 形式的路由规则和应用程序级别的规则相似, 只是, 在应用级别时, 用大括号来包裹参数名 (如 {controller}), 而在 Attribute 方案中, 是用中括号的, 它只能用两个值:[controller][action] 其他参数也是用大括号比如,[controlloer]/[action]/[id?] 会报错, 你得改为 [controller]/[action]/{id?}
RouteAttribute 既可以用于 Controller 类型, 也可能用于单个 Action 方法上我举个例子, 像这样
- [Route("hello/[controller]/[action]")]
- public class SomethingController : Controller
- {
- [Route("{name?}")]
- public IActionResult SayHi(string name)
- {
- }
- }
在类上应用用的 Attribute 中, 可以使用这样的 URL :http://localhost:999/hello/something/sayhi 而在 SayHi 方法上, 又用了 Route Attribute, 指定了一个附加参数 name, 并且是可选的于是它可以与类上的 Route attribute 合并, 变成: http://localhost:999/hello/something/sayhi/Peter 这时, 字符串 Peter 会传给 SayHi 方法的 name 参数, 因为, 参数的名字与 Route 中的参数名是相同的, 都叫 name 如果 SayHi 中的参数名不叫 name, 那你得运用一下 FromRouteAttribute 了就像这样
- [Route("{name?}")]
- public IActionResult SayHi([FromRoute(Name = "name")]string who)
- {
- }
如果你希望 URL 中给 name 传入 int 类型的值, 你还可以限制它
[Route("{name:int}")]
其实这些约束条件对应的是 Microsoft.AspNetCore.Routing.Constraints 命名空间下面的类型
Route Data
Route data 其实就是一个字典, 存放的就是 URL 路径规则中参数与值的 key-value 对这个很简单, 我举个例子, 你就明白了
咱们就直接用上面那个例子吧
- [Route("hello/[controller]/[action]")]
- public class SomethingController : Controller
- {
- [Route("{name?}")]
- public IActionResult SayHi([FromRoute(Name = "name")]string who)
- {
- return Json(RouteData.Values);
- }
- }
在 SayHi 方法中, 咱们把 route data 返回
运行应用后, 输入地址: http://localhost/hello/something/sayhi/Tom, 得到的输出如下:
不用我解释了吧
给路由命名
上面的都是 F 话, 本小节才是本文的主题我们回头看看上面老周举过例的那个 route
- app.UseMvc(route =>
- {
- route.MapRoute("main", "{controller=Students}/{action=List}/{sid?}");
- route.MapRoute("edit_post", "{controller}-{action}");
- });
每条路由规则都会有自己的 name, 为啥要命名? 最直接的理由是为了唯一标识每条规则除了此因素外, 我们可以在开发过程中选择使用哪条规则, 有了 name, 想找出某条规则就好办了, 就好比你上学的时候, 老师点名, 要么点姓名, 要么点学号
基于 Attribute 的路由规则也可以命名的, 例如
[Route("hello/[controller]/[action]", Name = "prv")]
这样就把它命名为 prv 了, 你还可以这样写
[Route("hello/[controller]/[action]", Name = "[controller]_[action]")]
这样也可以用 Controller 和 Action 的名字生成一个唯一的名字, 比如 Something_SayHi 但是这种方法太动态了, 好像不那么好操控, 还是用一个固定的名字好一点
要在开发的时候选择使用指定的 URL 路由, 需要在 Razor 页中添加 Tag Helper, 标记帮助类可以扩展 HTML 标记的某些功能在需要使用 tag helper 的页面, 或者统一在 _ViewImports.cshtml 页中加入这些指令
@addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers
格式是这样的:
<类型全路径>, <程序集>
类型写在前面 (包括 namespace 名), 程序集名写在后面, 用逗号分隔这里用星号(*) 是最爽的, 它是通配符, 表示引入所有 tag helper 类型这样快捷, 一行代码了事
然后在 HTML 中你这样写
- <form method="post"
- asp-route="edit_post">
- <div class="form-group">
- <label asp-for="Name"></label>
- <input asp-for="Name" class="form-control"/>
- <span asp-validation-for="Name" class="text-danger"></span>
- </div>
- <div class="form-group">
- <label asp-for="Age"></label>
- <input asp-for="Age" class="form-control"/>
- <span asp-validation-for="Age" class="text-danger"></span>
- </div>
- <input asp-for="ID"/>
- <button type="submit" class="btn btn-dark">提交</button>
- </form>
其他代码你不用看了, 只看这一句就够了:
asp - route = "edit_post"
它的意思就是使用我刚刚定义的那条规则
route.MapRoute("edit_post", "{controller}-{action}");
所以, 在运行后就会生成这样的 HTML
- <form method="post" action="/Students-Editdata">
- <div class="form-group">
此处省略 1650 个字
</form>
因为我定义的规则是 {controller}-{action}的形式, 所以, Controller 是 Students,Action 是 Editdata, 连起来就是 Students-Editdata
那么, 这里它为什么能识别出 controller 和 action 的值呢, 你看看我的代码就知道了
- public class StudentsController : Controller
- {
- readonly StudentDBContext m_context;
- // 接收依赖注入
- public StudentsController(StudentDBContext c)
- {
- m_context = c;
- }
- public IActionResult List()
- {
- var q = from s in m_context.Students
- orderby s.ID
- select s;
- return View(q.ToList());
- }
- /***************************************************/
- // 以下方法用于编辑页
- [HttpGet]
- public IActionResult Editdata([FromRoute(Name = "sid")] int id)
- {
- var q = from s in m_context.Students
- where id == s.ID
- select s;
- Student stu = q.FirstOrDefault();
- if(stu == null)
- {
- return Content("在地球上找不到此学员");
- }
- return View(stu);
- }
- [HttpPost]
- public IActionResult Editdata(Student s)
- {
- if (ModelState.IsValid == false)
- {
- return View(s);
- }
- m_context.Students.Update(s);
- m_context.SaveChanges();
- return RedirectToAction(nameof(List));
- }
- }
我定义了 Editdata 方法的重载, 一个用于 get 请求, 一个用于 post 请求, form 是以 post 方式提交, 因此它能自动识别出 controller 和 action 的名字
那万一, 如果不是同名的呢, 好办你用 asp-route-<value> 来指定各个参数的值比如这样
- <form method="post"
- asp-route="edit_post"
- asp-route-controller="Demo"
- asp-route-action="Runwork"
- asp-route-sid="1">
在 asp-route- 后面直接跟上路由规则参数的名称就可以了
有一点要注意, asp-route 与 asp-controllerasp-action 是会冲突的, 如果你用了这两个标记, 就不能用 asp-route 标记了, 当然 asp-route-xxx 是可以用的
来源: https://www.cnblogs.com/tcjiaan/p/8439178.html