【ASP.NET Core】给路由规则命名有何用处
上一篇中老周给伙伴们介绍了自定义视图搜索路径的方法,本篇咱们扯一下有关 URL 路径规则的名称问题。在扯今天的话题之前,先补充点东东。在上一篇中设置视图搜索路径时用到三个有序参数:{2}{1}{0},分别是 Area、Controller、Action。其中说到几个特殊的视图,如_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-controller、asp-action是会冲突的,如果你用了这两个标记,就不能用 asp-route 标记了,当然 asp-route-xxx 是可以用的。
好了,今天的内容就扯到这儿了,顺便把示例的代码也传上来,以供伙伴们娱乐。
【ASP.NET Core】给路由规则命名有何用处的更多相关文章
- ASP.NET Core 属性路由 - ASP.NET Core 基础教程 - 简单教程,简单编程
原文:ASP.NET Core 属性路由 - ASP.NET Core 基础教程 - 简单教程,简单编程 ASP.NET Core 属性路由 经过前面章节的学习,想必你已经对 ASP.NET Core ...
- ASP.NET Core的路由[5]:内联路由约束的检验
当某个请求能够被成功路由的前提是它满足某个Route对象设置的路由规则,具体来说,当前请求的URL不仅需要满足路由模板体现的路径模式,请求还需要满足Route对象的所有约束.路由系统采用IRouteC ...
- ASP.NET Core的路由[3]:Router的创建者——RouteBuilder
在<注册URL模式与HttpHandler的映射关系>演示的实例中,我们总是利用一个RouteBuilder对象来为RouterMiddleware中间件创建所需的Router对象,接下来 ...
- ASP.NET Core的路由[2]:路由系统的核心对象——Router
ASP.NET Core应用中的路由机制实现在RouterMiddleware中间件中,它的目的在于通过路由解析为请求找到一个匹配的处理器,同时将请求携带的数据以路由参数的形式解析出来供后续请求处理流 ...
- ASP.NET Core的路由[1]:注册URL模式与HttpHandler的映射关系
ASP.NET Core的路由是通过一个类型为RouterMiddleware的中间件来实现的.如果我们将最终处理HTTP请求的组件称为HttpHandler,那么RouterMiddleware中间 ...
- ASP.NET Core 入门教程 3、ASP.NET Core MVC路由入门
一.前言 1.本文主要内容 ASP.NET Core MVC路由工作原理概述 ASP.NET Core MVC带路径参数的路由示例 ASP.NET Core MVC固定前/后缀的路由示例 ASP.NE ...
- ASP.NET Core 入门笔记4,ASP.NET Core MVC路由入门
敲了一部分,懒得全部敲完,直接复制大佬的博客了,如有侵权,请通知我尽快删除修改 摘抄自https://www.cnblogs.com/ken-io/p/aspnet-core-tutorial-mvc ...
- ASP.NET Core的路由[4]:来认识一下实现路由的RouterMiddleware中间件
虽然ASP.NET Core应用的路由是通过RouterMiddleware这个中间件来完成的,但是具体的路由解析功能都落在指定的Router对象上,不过我们依然有必要以代码实现的角度来介绍一下这个中 ...
- 如何在ASP.NET Core中构造UrlHelper,及ASP.NET Core MVC路由讲解
参考文章: Unable to utilize UrlHelper 除了上面参考文章中介绍的方法,其实在ASP.NET Core MVC的Filter拦截器中要使用UrlHelper非常简单.如下代码 ...
随机推荐
- Codility:Titanium 2016 challenge:BracketsRotation
发现codility上很难找到自己的代码,所以来存一下. 用的一种水法,不知道是结论对还是数据水. 处理出所有极大合法串最后就只剩)))((((状的括号,然后枚举右端点,左端点单调. 但是未匹配点数量 ...
- Codeforces 833E Caramel Clouds
E. Caramel Clouds time limit per test:3 seconds memory limit per test:256 megabytes input:standard i ...
- 二分查找c++简单模板
//数组a[]中有n各元素,已经按升序排序,待查找的元素x sort(a,a+n); //升序排序 template<class Type> int BinarySearch(Type a ...
- ACM_高次同余方程
/*poj 3243 *解决高次同余方程的应用,已知 X^Y = K mod Z, 及X,Z,K的值,求 Y 的值 */ #include<cstdio> #include<cstr ...
- Ajax 案例之三级联动
每次在博客园网站写博客,格式真的好难搞,还望好心人告知更好的编辑工具.接下来进入正题:三级联动(其效果演示可看我的博文Ajax 学习总结 末尾). 数据表设计(Oracle) 新建数据表 Employ ...
- Git分支管理及常见操作
众所周知,使用Git分支,我们可以从开发主线上分离开来,然后在不影响主线的同时继续工作. 既然要使用Git分支,这里就涉及到Git分支的管理及常见操作,如列出分支,分支的创建,分支的删除,分支的合并等 ...
- Logback日志配置的简单使用
Logback介绍 Logback是由log4j创始人设计的又一个开源日志组件.logback当前分成三个模块:logback-core,logback- classic和logback-access ...
- mysql之repair table 修复表札记
REPAIR [LOCAL | NO_WRITE_TO_BINLOG] TABLE tbl_name[,tbl_name] ... [QUICK] [EXTENDED] [USE_FRM] REP ...
- VisualSVN Server启动错误(0x8007042a)
SVN Server启动错误(0x8007042a) 原因是SVN Server端口被占用 打开VisualSVN Server, 菜单->操作->Properties->Net ...
- MySQL密码忘了怎么办?MySQL重置root密码方法
本文主要介绍Windows和Linux系统下忘记密码重置root密码的方法,需要的朋友可以参考下. MySQL有时候忘记了root密码是一件伤感的事.这里提供Windows 和 Linux 下的密码重 ...