ASP.NET MVC站点带有以下默认根,当访问该站点的根(例如http://localhost:12345
)时,该根执行主控制器的索引操作
routes.MapRoute(
name: "Default",
url: "{controller}/{action}/{id}",
defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional }
);
那么,当找不到路线时,这是一种倒退吗?
没那么快。如果我们尝试导航到http://localhost/a/b
(其中不存在"a"控制器),它将不会执行Home控制器的Index操作-将返回错误。
为什么在这种情况下无法执行Home/Index,但在路径中完全不输入任何内容就可以执行Home/Inindex?
这里的逻辑是什么?为什么这条路线被称为"默认"?
我看过很多关于路由的文章,但没有一篇对此进行解释。
相关问题
在其他情况下,"默认值"似乎更像是一条路线的映射。例如
url: "abc/def", defaults: new { controller = "bongo", action = "bingo" }
这只是在bongo控制器上执行宾果游戏操作——只要输入了确切的url"abc/def"。为什么它被称为"违约"——这个词似乎并不合适。(删除"默认值"有任何效果吗,我看到它被省略了)。
在默认路由中,它看起来更像是一个回退,在后一个示例中,它更像是映射?
我觉得我在概念层面上缺少了一些东西。
thx。
逻辑虽然一开始不是很直观,但实际上非常简单。
一般来说,当传入请求发生时,会发生两种不同的情况。
- 尝试匹配路线
- 为MVC提供一组路由值(以及可选的路由元数据),用于查找操作方法
当传入请求发生时,MVC执行路由表中第一个路由的GetRouteData
方法。如果不匹配,它将尝试第二次、第三次,依此类推,直到找到匹配。
如果最终在路由表中没有匹配,RouteCollection.GetRouteData
(调用每条路由的GetRouteData
的方法)将返回null
。如果找到匹配,匹配路由中的路由值将返回到MVC,MVC在那里使用它们来查找控制器和要执行的操作。请注意,在这种情况下,不会检查路由表中的其他路由是否匹配。换句话说,第一场比赛总是赢。
匹配过程依赖于三件事:
- 占位符
- 文字段
- 限制
占位符
您询问的部分是占位符,以及为什么在没有值的情况下它们匹配。占位符(即{controller}
)的作用类似于变量。他们会接受任何价值。它们可以初始化为默认值。如果它们没有初始化为默认值,则需要位于URL中才能匹配。
考虑路线定义中的defaults
:
defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional }
如果URL中未提供占位符,则将使用这些值(作为RouteValues中的匹配和输出)。
按照同样的逻辑,默认情况下,所有这些URL都将到达HomeController.Index
操作方法。
/
/Home
/Home/Index
/Home/Index/Foo
/Home/Index/123
URL:
/
如果将URL/
传递到框架,它将匹配Default
路由并将其发送到HomeController.Index
方法,因为如果未提供默认值,则默认值为Home
和Index
。在这种情况下,路由值为:
| Key | Value |
|-------------|-------------|
| controller | Home |
| action | Index |
| id | {} |
URL
/Home
请注意,您也可以只传递控制器名称/Home
。路由表看起来完全一样。
| Key | Value |
|-------------|-------------|
| controller | Home |
| action | Index |
| id | {} |
但是,在这种情况下,controller
值是通过URL中的占位符传入的。它不再考虑路由的默认controller
值,因为URL中已经提供了一个值。
URL:
/Test
遵循相同的逻辑,URL/Test
将产生以下路由表。
| Key | Value |
|-------------|-------------|
| controller | Test |
| action | Index |
| id | {} |
路由不会自动检查控制器是否真的存在。它只是提供了价值。如果应用程序中没有名为TestController
的控制器执行Index
操作,则会导致错误。
这就是为什么您上面提供的URL/a/b
不起作用的原因——您的项目中没有名为AController
的控制器,其操作名为B
。
如果占位符未初始化为默认值,则需要位于URL中,以便路由匹配。
routes.MapRoute(
name: "Default",
url: "{controller}/{action}/{id}",
defaults: new { action = "Index", id = UrlParameter.Optional }
);
因此,给定上述路由,它将匹配URL/Home
:
| Key | Value |
|-------------|-------------|
| controller | Home |
| action | Index |
| id | {} |
但它与URL/
不匹配,因为控制器并没有默认值。
文字段
routes.MapRoute(
name: "Foo",
url: "abc/def",
defaults: new { controller = "bongo", action = "bingo" }
);
上述路由在URL中使用文字段。为了将路由视为匹配,文字段需要完全匹配(不区分大小写)。因此,唯一匹配的URL是abc/def
或这两个段的任何大写/小写组合。
然而,这种情况在一个方面有所不同。无法通过URL传递值。因此,必须设置默认值(至少对于controller
和action
),以便将任何路由值传递给MVC。
| Key | Value |
|-------------|-------------|
| controller | bongo |
| action | bingo |
MVC框架要求有一个BongoController
和一个名为Bingo
的操作,否则这个路由将失败得很惨。
限制
约束是路由匹配所需的额外条件。每个约束返回一个布尔值(匹配/不匹配)响应。每条管线可以有0到多个约束。
RegEx约束
routes.MapRoute(
name: "CustomRoute",
url: "{placeholder1}/{action}/{id}",
defaults: new { controller = "MyController" },
constraints: new { placeholder1 = @"^house$|^car$|^bus$" }
);
匹配
/house/details/123
/car/foo/bar
/car/bar/foo
与不匹配
/house/details
/bank/details/123
/bus/foo
/car
/
自定义约束
public class CorrectDateConstraint : IRouteConstraint
{
public bool Match(HttpContextBase httpContext, Route route, string parameterName, RouteValueDictionary values, RouteDirection routeDirection)
{
var year = values["year"] as string;
var month = values["month"] as string;
var day = values["day"] as string;
DateTime theDate;
return DateTime.TryParse(year + "-" + month + "-" + day, System.Globalization.CultureInfo.InvariantCulture, DateTimeStyles.None, out theDate);
}
}
routes.MapRoute(
name: "CustomRoute",
url: "{year}/{month}/{day}/{article}",
defaults: new { controller = "News", action = "ArticleDetails" },
constraints: new { year = new CorrectDateConstraint() }
);
注意:分配给约束的值(在上述情况下为year =
)与传递给自定义约束的值相同。但是,自定义约束没有义务使用此值。有时,使用任何值都没有意义,在这种情况下,可以在controller
上设置约束。
匹配
/2012/06/20/some-great-article
/2016/12/25/all-about-christmas
与不匹配
/2012/06/33/some-great-article
/2012/06/20
/99999/09/09/the-foo-article
在大多数情况下,只要URL中有占位符(如{controller}
或{something}
),就应该使用约束,以防止它们与不应该匹配的值匹配。
文本段(或带有占位符的部分文本段)、约束和所需值通常都是在路由设置中使用的非常好的内容。它们有助于确保您的路由不会在如此大的范围内匹配,从而阻止执行在路由表中在它们之后注册的路由。
占位符与任何值匹配,因此通常不建议在任何路由中仅使用占位符,除非与约束一起使用,否则应在
Default
路由中使用占位符。StackOverflow上的许多人建议完全删除Default
路由,以确保意外路由不会起作用,我不一定不同意这种观点。
进一步阅读
- ASP.NET路由(MSDN)
- 为什么在asp.net mvc中,先绘制特殊路线,然后再绘制常见路线