.NetCore MVC中的路由(1)路由配置基础
.NetCore MVC中的路由(1)路由配置基础
0x00 路由在MVC中起到的作用
前段时间一直忙于别的事情,终于搞定了继续学习.NetCore。这次学习的主题是MVC中的路由。路由是所有MVC框架都会实现的一个组件,核心功能就是根据接收到的Http请求中的Path(对于http://localhost/Home/Index/12?test=555 来说,http是协议,localhost是域,Home/Index/12是Path,test=555是参数)部分,依次和路由规则集合中的规则进行匹配,匹配成功后由对应的Controller中的对应Action进行Http请求的处理。匹配不到则返回404错误。

大多数MVC框架路由规则的配置都大同小异,一般都是通过模板的方式来配置路由规则。有的还支持在Controller和Action上通过Attribute(Java中叫注解)进行更细粒度的配置。
.NetCore MVC支持通过全局的路由模板配置路由规则,也支持在Controller和Action上通过Attribute进行细粒度的路由配置。下面先说一下在Startup.cs中配置全局路由规则。
0x01 在Startup.cs中配置路由
所谓的路由的模板就是一串字符串,当接收到Http请求后取出其中的Path部分,和模板进行对照,如果匹配模板则路由到对应的Controller和Action进行处理。我们可以在Startup.cs文件中的Configure方法中,添加MVC功能时进行路由配置,例如:
app.UseMvc(routes =>
{
routes.MapRoute(
name: "default",
template: "{controller}/{action}/{id}");
});
其中name为路由规则的名称,template为路由模板。这也引出了我们第一个概念,路由模板中的变量。
1.路由模板中的变量
在模板"{controller }/{action }/{id}"中,用花括号括起来的是路由模板中的变量。例如其中变量的作用并不是必须在Path中匹配某个固定的字符串,而是起到一个占位的作用,例如上面的模板就可以匹配由“/”隔开的共三部分的Path,例如a/b/c可以匹配成功。而各个变量的值从Path中对应部分提取出来。例如
Home/Index/12可以匹配,其中controller为Home,action为Index,id为12
Home/Index则匹配失败,因为只有2部分
Home/Index/12/34同样匹配失败,因为超过了3部分。
模板匹配成功后,会根据controller和action提取出的值路由:
Home/Index/12会路由到HomeController的Index方法,变量id为12
Test/Show/ab会路由到TestController的Show方法,变量id为ab
2.变量值得获取
在Index或Show方法中,我们可以有两种方法提取变量:
一种是在方法的参数列表中加入和变量相同名称的参数,MVC会自动从变量列表中寻找并转换为对应类型:
public IActionResult Index(string id, string controller, string action)
{
ViewData["Message"] = "id is " + id + ", controller is " + controller + ", action is " + action;
return View();
}
另一种就是从RouteData中取出:
public IActionResult Index()
{
var controller = RouteData.Values["controller"].ToString();
var action = RouteData.Values["action"].ToString();
var id = RouteData.Values["id"].ToString();
ViewData["Message"] = "id is " + id + ", controller is " + controller + ", action is " + action;
return View();
}
路由模板中的变量名称是可以自己定义的,但controller和action(包括后面讲的area)都是比较特殊的变量。其中controller提取出的值作为Controller的名称,action提取出的值作为Controller中方法的名称。为了让每条路由规则都能够路由到Controller和Action,在路由模板中都应该出现controller和action变量,但我们也可以给controller和action变量指定默认值,这样在Path中省略了这部分时会用默认值代替。
3.变量的默认值
由两种方法可以配置变量的默认值:
app.UseMvc(routes =>
{
routes.MapRoute(
name: "default",
template: "{controller=Home}/{action=Index}/{id=0}");
});
或者
routes.MapRoute(
name: "default",
template: "{controller}/{action}/{id}",
defaults: new
{
controller = ”Home”,
action = ”Index”,
id = ,
});
这样配置后Path中带有默认值的部分可以省略,省略的规则和C#中带默认值的参数一样,例如:
空Path会被路由到HomeController,Index方法
Test会被路由到TestController,Index方法
Test/Show依然会被路由到TestController,Show方法
一般我会用第一种方法配置默认值,更加直观和方便。但有时候有些需求是第一种方法难以做到的。例如我想给TestController的Show方法配置路由为TestShow,使用第一种方法可以这样配置:”TestShow/{controller=Test}/{action=Show}”,这样配置当Path为TestShow时的确可以路由到TestController的Show方法,但当Path为TestShow/Home/Index时会路由到HomeController的Index方法。
使用第二种方法配置:
routes.MapRoute(
name: "test",
template: "TestShow",
defaults: new
{
controller = ”Test”,
action = ”Show”,
});
当Path为TestShow时可以路由到TestController的Show方法,但Path为Test/Home/Index则无法匹配模板。关于细粒度的路由配置更好的方法是给Test方法使用Route特性(Attribute)进行配置,后面会说到。
4.路由规则中的静态字符
除了使用变量来配置路由模板,还可以使用静态字符串。静态字符串可以单独使用,也可以与变量混合使用。
例如模板为:
”Durow/{controller}/{action}”
Durow/Home/About会路由到HomeController,About方法
Durow/Test/Show会路由到TestController,Show方法
也可以把静态字符和变量混合起来,例如配置模板为:
”My{controller}/My{action}”
MyHome/MyAbout会被路由到HomeController,About方法
MyTest/MyShow会被路由到TestController,Show方法
5.使用?标记变量可选
除了通过给变量提供默认值使其可选外,也可以使用?把变量标记为可选。例如模板
“{controller}/{action}/{id?}”
其中id为可选变量,这样配置后
Home/Index和Home/Index/12都会成功匹配。
6.使用*提取Path中剩余的所有部分
如果一个模板需要匹配包含任意多个部分(Segments)的Path,可以使用*符号指定变量,使用*制定过的变量会把Path中匹配完成后剩余部分全部提取出来,例如模板:
”{controller}/{action}/{id?}/{*others}”
Home/Index/12/a/b/c/d,会路由到HomeController的Index方法,id为12,others为a/b/c/d
实际上仅从模板匹配的角度来说,上面的模板可以匹配所有的Path。唯一的问题就是匹配后对应的Controller和Action可能不存在。
7.多条路由规则的选择
实际应用中很可能会配置多条路由规则,当接收到Path时很可能不止一条规则能够匹配。
最简单的,我们配置以下两条模板:
“{controller }/{action =About}”
“{controller }/{action =Index }”
当Path为Home时两条路由都能匹配,那要怎么选择呢?其实很简单粗暴,就是看哪条路由在前面。也就是说Path一旦成功匹配到模板后就会立即实施路由并忽略后面的模板。对于上面的配置来说Home会被路由到HomeController的About方法。所以在配置路由时一定要注意顺序。
0x02 使用Attribute配置路由
除了在Startup.cs中配置全局路由规则外,也可以针对单个Controller和其中的Action配置路由。方法就是在Controller类和Action方法上使用Route特性。例如在TestController的Show方法上使用Route特性:
[Route("TestShow")]
public IActionResult Show()
{
return View();
}
当Path为TestShow时,即可路由到TestController的Show方法。
上面我们在介绍默认值时提到过,通过全局模板配置:
routes.MapRoute(
name: "test",
template: "TestShow",
defaults: new
{
controller = ”Test”,
action = ”Show”,
});
也可以达到同样的目的。不过区别在于,使用后一种方法时,如果还有”{controller}/{action}”这样的模板,除了TestShow外,当Path为Test/Show可以匹配这个模板并路由到TestController的Show方法。而通过在Show方法上配置Route特性后,只有TestShow才可以路由,即使同时存在”{controller}/{action}”这样的模板,Test/Show也无法路由。
第一次接触用Route特性配置路由时,我很疑惑路由组件是如何把Path路由到对应的Controller和Action的,后来下了个断点看了下RouteData对象,发现对于配置了路由的Action方法,其controller为方法所在的Controller的名称,action为方法的名称,而且在Route特性配置的路由模板中不能够使用{controller}变量和{action}变量。这样就保证了匹配模板的Path总能路由到这个Action。
对于在Controller类上配置的Route特性最终会分别配置到Controller中的每个Action上。例如我们在TestController上配置Route(“TestShow”),实际上就是给每个方法配置了Route(“TestShow"),所以当Path为TestShow时会报错,提示有两个action满足匹配。那么应当如何给Controller通过Route配置路由呢,可以使用[controller]和[action]。
Route特性中的[controller]和[action]
对于[controller]和[action]我也不知道该怎么叫,不能叫变量,功能上类似占位符。当我们在Controller类用Route特性配置路由时,如果使用了[controller]和[action],这样当Route特性给Controller中每个Action配置路由时,[controller]会被替换为Controller名称,[action]会被替换为Action名称。举个例子还是给TestController配置Route特性,配置为Route(“durow/[controller]/[action]”),这样对于其中的Index方法来说,其路由模板为”durow/Test/Index”,controller为Test,action为Index。而对于Show方法来说路由模板为”durow/Test/Show”,controller为Test,action为Show。前面说过MVC会为每个Action创建一个ActionDescriptor对象存储这个Action的路由信息。对于配置了Route特性的Action(再重复一下,给Controller类配置Route特性相当于给Controller中的每个Action配置Route特性),其ActionDescriptor中会有一个AttributeRouteInfo对象,对于未配置Route特性的Action,该对象为空。AttributeRouteInfo中包含了路由模板信息。

所以对于上面TestController的Route特性的配置,配置为Route(“durow/Test/[action]”)也能达到同样的效果。不过使用Route(“durow/[controller]/[action]”)语义更强更通用。
在Route特性中使用变量
在Route特性中配置模板也是可以使用变量的,同样可以使用?标记变量可选。例如可以给TestController配置Route(“durow/[controller]/[action]/{id?}”)。但需要注意的是Route特性的模板中变量不能使用默认值(包括[controller]和[action]),也不能使用*提取Path所有剩余部分。
0x03 写在最后
啰啰嗦嗦居然写了这么多,其实实际使用中很可能用不到多么复杂的路由,一般一条通用规则,一条Area相关的规则就可以了。不过详细了解了路由规则,当以后遇到有些奇葩的特殊需求时能够有更加开阔的思路。后面讲讨论一下路由模板中的约束和自定义约束。再后面讨论一下使用Areas。
更多内容欢迎访问我的博客:http://www.durow.vip
.NetCore MVC中的路由(1)路由配置基础的更多相关文章
- .NetCore MVC中的路由(2)在路由中使用约束
p { margin-bottom: 0.25cm; direction: ltr; color: #000000; line-height: 120%; orphans: 2; widows: 2 ...
- YbSoftwareFactory 代码生成插件【二十四】:MVC中实现动态自定义路由
上一篇介绍了 公文流转系统 的实现,本篇介绍下MVC下动态自定义路由的实现. 在典型的CMS系统中,通常需要为某个栏目指定个友链地址,通过指定友链地址,该栏目的地址更人性化.方便记忆,也有利用于搜索引 ...
- .NetCore Linux中安装Grafana界面及配置InfluxDB相关设置
前面的文章已经安装好了InfluxDB 安装 wget https://s3-us-west-2.amazonaws.com/grafana-releases/release/grafana-5.1. ...
- ASP.NET MVC 及 Areas 简单控制路由
ASP.NET MVC中怎么去控制路由,这个想关的文章很多,我在这里就是自我总结一下,仅供参考. 1.我们新建一个项目,查看RouteConfig.cs,代码如下: public static voi ...
- ASP.NET没有魔法——ASP.NET MVC 直连路由(特性路由)
之前对Controller创建的分析中,知道了Controller的创建是有两个步骤组成,分别是Controller的类型查找以及根据类型创建Controller实例. 在查询Controller的类 ...
- ASP.NET Core 3.0中使用动态控制器路由
原文:Dynamic controller routing in ASP.NET Core 3.0 作者:Filip W 译文:https://www.cnblogs.com/lwqlun/p/114 ...
- MVC中使用Hangfire执行定时任务
需求描述 项目中有一个通知公告的功能,在后台管理员添加公告后需要推送消息给所有注册用户,让其查看消息.消息推送移动端采用极光推送,但是消息在何时发送是个问题,比如说有一个重要的会议通知,可能希望在会议 ...
- mvc中Url.RouteUrl或者Html.RouteLink实现灵活超链接,使href的值随路由名称或配置的改变而改变[bubuko.com]
mvc,超链接除了直接写在a标签的href内还可以使用路由规则来生成,这样在改变了路由规则或者路由名称时不用再去代码中更改href的值,而且还容易遗漏.借助Url.RouteUrl或者Html.Rou ...
- ASP.NET Core MVC 中两种路由的简单配置
1.全局约定路由 这种方式配置优先级比较低,如果控制器或者方法上标记了特性路由那么优先走特性路由. 当建立好一个mvc项目里,路由都是默认配置好的. 如果建立的是空项目那么需要手动配置: 1.需要在C ...
随机推荐
- 【原】Android热更新开源项目Tinker源码解析系列之二:资源文件热更新
上一篇文章介绍了Dex文件的热更新流程,本文将会分析Tinker中对资源文件的热更新流程. 同Dex,资源文件的热更新同样包括三个部分:资源补丁生成,资源补丁合成及资源补丁加载. 本系列将从以下三个方 ...
- Xshell 连接CentOS服务器解密
平台之大势何人能挡? 带着你的Net飞奔吧!http://www.cnblogs.com/dunitian/p/4822808.html Xshell生成密钥key(用于Linux 免密码登录)htt ...
- MyEclipse生成注册码
今天正在使用的MyEclipse出现了使用过期,在网上发现一个可以生成注册码的程序,现在分享给各位. /** * myEclipse生成注册码 * 点击顶部:MyEclipse --> subs ...
- .NET Core的日志[1]:采用统一的模式记录日志
记录各种级别的日志是所有应用不可或缺的功能.关于日志记录的实现,我们有太多第三方框架可供选择,比如Log4Net.NLog.Loggr和Serilog 等,当然我们还可以选择微软原生的诊断框架(相关A ...
- win8.1硬盘安装ubuntu14.04双系统
在网上找了很多方法都失败了,原因是大多数方法都是用mbr方式安装的,如grub4dos,easybcd.以至于连自己都怀疑win8能不能用硬盘安装,差点就去买个u盘来安装了,就在打算放弃的时候在ubu ...
- BPM配置故事之案例5-必填与水印文本
物资申请表改好了,但是没过两天老李又找来了. 老李:这个表格每次都是各个部门发给我们,再由我们采购部来填,太影响效率了,以后要让他们自己填. 小明:那就让他们填呗,他们有权限啊. 老李:可是他们说不会 ...
- Android 旋转屏幕--处理Activity与AsyncTask的最佳解决方案
一.概述 运行时变更就是设备在运行时发生变化(例如屏幕旋转.键盘可用性及语言).发生这些变化,Android会重启Activity,这时就需要保存activity的状态及与activity相关的任务, ...
- ubuntu15.04 nginx1.6.5 配置虚拟主机
1 在/etc/hosts 添加host 2 在/etc/nginx/nginx.conf中查看http里的include ****** /*.conf的路径,在此路径下添加一个新的******. ...
- ubuntu14.04下安装node.js
在网上查了下,起初是下载了一个node-v0.12.7-linux-x64.tar.gz,解压在/home/node路径下,然后在/etc/profile中添加如下命令: export NODE_HO ...
- 基于Node.js实现一个小小的爬虫
以前一直听说有爬虫这种东西,稍微看了看资料,貌似不是太复杂. 正好了解过node.js,那就基于它来个简单的爬虫. 1.本次爬虫目标: 从拉钩招聘网站中找出“前端开发”这一类岗位的信息,并作相应页面分 ...