概述
【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 路由规则—— 从[ROUTE(“HELLO/[CONTROLLER]/[ACTION]“)]引起的探索的全部内容,希望文章能够帮你解决ASP.NET CORE 路由规则—— 从[ROUTE(“HELLO/[CONTROLLER]/[ACTION]“)]引起的探索所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
发表评论 取消回复