.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)路由配置基础的更多相关文章

  1. .NetCore MVC中的路由(2)在路由中使用约束

    p { margin-bottom: 0.25cm; direction: ltr; color: #000000; line-height: 120%; orphans: 2; widows: 2 ...

  2. YbSoftwareFactory 代码生成插件【二十四】:MVC中实现动态自定义路由

    上一篇介绍了 公文流转系统 的实现,本篇介绍下MVC下动态自定义路由的实现. 在典型的CMS系统中,通常需要为某个栏目指定个友链地址,通过指定友链地址,该栏目的地址更人性化.方便记忆,也有利用于搜索引 ...

  3. .NetCore Linux中安装Grafana界面及配置InfluxDB相关设置

    前面的文章已经安装好了InfluxDB 安装 wget https://s3-us-west-2.amazonaws.com/grafana-releases/release/grafana-5.1. ...

  4. ASP.NET MVC 及 Areas 简单控制路由

    ASP.NET MVC中怎么去控制路由,这个想关的文章很多,我在这里就是自我总结一下,仅供参考. 1.我们新建一个项目,查看RouteConfig.cs,代码如下: public static voi ...

  5. ASP.NET没有魔法——ASP.NET MVC 直连路由(特性路由)

    之前对Controller创建的分析中,知道了Controller的创建是有两个步骤组成,分别是Controller的类型查找以及根据类型创建Controller实例. 在查询Controller的类 ...

  6. ASP.NET Core 3.0中使用动态控制器路由

    原文:Dynamic controller routing in ASP.NET Core 3.0 作者:Filip W 译文:https://www.cnblogs.com/lwqlun/p/114 ...

  7. MVC中使用Hangfire执行定时任务

    需求描述 项目中有一个通知公告的功能,在后台管理员添加公告后需要推送消息给所有注册用户,让其查看消息.消息推送移动端采用极光推送,但是消息在何时发送是个问题,比如说有一个重要的会议通知,可能希望在会议 ...

  8. mvc中Url.RouteUrl或者Html.RouteLink实现灵活超链接,使href的值随路由名称或配置的改变而改变[bubuko.com]

    mvc,超链接除了直接写在a标签的href内还可以使用路由规则来生成,这样在改变了路由规则或者路由名称时不用再去代码中更改href的值,而且还容易遗漏.借助Url.RouteUrl或者Html.Rou ...

  9. ASP.NET Core MVC 中两种路由的简单配置

    1.全局约定路由 这种方式配置优先级比较低,如果控制器或者方法上标记了特性路由那么优先走特性路由. 当建立好一个mvc项目里,路由都是默认配置好的. 如果建立的是空项目那么需要手动配置: 1.需要在C ...

随机推荐

  1. React 入门教程

    React 起源于Facebook内部项目,是一个用来构建用户界面的 javascript 库,相当于MVC架构中的V层框架,与市面上其他框架不同的是,React 把每一个组件当成了一个状态机,组件内 ...

  2. ASP.NET Aries 入门开发教程4:查询区的下拉配置

    背景: 今天去深圳溜达了一天,刚回来,看到首页都是微软大法好,看来离.NET的春天就差3个月了~~ 回到正题,这篇的教程讲解下拉配置. 查询区的下拉配置: 1:查询框怎么配置成下拉? 在配置表头:格式 ...

  3. JavaScript Math和Number对象

    目录 1. Math 对象:数学对象,提供对数据的数学计算.如:获取绝对值.向上取整等.无构造函数,无法被初始化,只提供静态属性和方法. 2. Number 对象 :Js中提供数字的对象.包含整数.浮 ...

  4. git 命令

    切换仓库地址: git remote set-url origin xxx.git切换分支:git checkout name撤销修改:git checkout -- file删除文件:git rm  ...

  5. MVC Core 网站开发(Ninesky) 2.1、栏目的前台显示

    上次创建了栏目模型,这次主要做栏目的前台显示.涉及到数据存储层.业务逻辑层和Web层.用到了迁移,更新数据库和注入的一些内容. 一.添加数据存储层 1.添加Ninesky.DataLibrary(与上 ...

  6. .NET Core的日志[2]:将日志输出到控制台

    对于一个控制台应用,比如采用控制台应用作为宿主的ASP.NET Core应用,我们可以将记录的日志直接输出到控制台上.针对控制台的Logger是一个类型为ConsoleLogger的对象,Consol ...

  7. 通过 floating IP 访问 VIP - 每天5分钟玩转 OpenStack(126)

    前面我们是直接用 curl 测试 VIP,在更为真实的场景中通常会使用 floating IP 访问 VIP. 下面我们给 VIP 关联一个 floating IP,再进行测试. 访问 Project ...

  8. WebApi接口 - 如何在应用中调用webapi接口

    很高兴能再次和大家分享webapi接口的相关文章,本篇将要讲解的是如何在应用中调用webapi接口:对于大部分做内部管理系统及类似系统的朋友来说很少会去调用别人的接口,因此可能在这方面存在一些困惑,希 ...

  9. [C#][算法] 用菜鸟的思维学习算法 -- 马桶排序、冒泡排序和快速排序

    用菜鸟的思维学习算法 -- 马桶排序.冒泡排序和快速排序 [博主]反骨仔 [来源]http://www.cnblogs.com/liqingwen/p/4994261.html  目录 马桶排序(令人 ...

  10. 【Java每日一题】20170103

    20161230问题解析请点击今日问题下方的"[Java每日一题]20170103"查看(问题解析在公众号首发,公众号ID:weknow619) package Jan2017; ...