MVC 5 多个路由到同一控制器
MVC 5 Multiple Routes to Same Controller
在我们的 RouteConfig.cs
文件中,我们有以下默认路由:
routes.MapRoute(
name: "Default",
url: "{controller}/{action}/{id}",
defaults: new { controller = "Original", action = "Index", id = UrlParameter.Optional },
namespaces: new[] { "Path.To.Controllers" }
);
我们的应用程序分为几个不同的 "Areas"。这条特定的路线工作得很好。
我们被要求更改我们的一个 URL,但是底层代码库是相同的。为了避免破坏现有链接,我想设置我的控制器以支持两种不同的路由:
这是原始 URL 的示例:
website.com/MyArea/Original
有了前面提到的 "Default" 路由,这将被定向到 MyArea
区域中的 OriginalController
,并且会触发默认的 Index
动作,因为 none 已指定。
我的目标是设置另一个 URL,它也将自己定向到 OriginalController
。也就是说,
website.com/MyArea/Other
应该路由到 MyArea
区域中的 OriginalController
,并点击默认的 Index
动作。
我已将以下内容添加到 RouteConfig.cs
文件中:
routes.MapRoute(
name: "Other",
url: "Other/{action}/{id}",
defaults: new { controller = "Original", action = "Index", id = UrlParameter.Optional },
namespaces: new[] { "Path.To.Controllers" }
);
我发现 Default
路由配置 总是 用于支持 Other
路由配置,这会导致绑定问题声明“OtherController
找不到”。我怀疑这是因为它们在 url
模板中有一个非常相似的签名,但我不完全确定如何解决这个问题。
我知道还有一个 Route
属性,我不反对使用它。不幸的是,我没有成功地正确设置。
在研究并尝试了几种不同的组合后,我仍然无法让两个 URL 都路由到一个控制器。
我做错了什么?
我能够在控制器本身上使用 RouteAttribute
获得预期的结果(感谢@Michael 提供的资源并让我再次查看 RouteAttribute),而不是传统的 MapConfig
路由。正如我在上面的问题中所描述的,我在尝试 Route
方法时遇到了困难,因为我收到了 404 错误,指出 "resource could not be found"。
事实证明,上述错误是由于我的属性路由没有以正确的顺序连接,这迫使在我的路由属性上使用常规路由(例如默认 MapConfig)。
我偶然发现 this SO post 其中指出:
You are probably combining convention based routing with attribute
routing, and you should register your areas after you map the
attribute routes.
The line
AreaRegistration.RegisterAllAreas();
should be called AFTER this line:
routes.MapMvcAttributeRoutes();
使用区域时,必须在注册属性路由后注册这些区域。我最初是在 Globas.asax.cs
的 Application_Start
方法中注册我的区域,该方法在 RouteConfig.RegisterRoutes
之前调用。我将此注册移动到 RouteConfig.cs
文件中 MapMvcAttributeRoutes
调用的正下方,这允许控制器上的以下路由属性按预期工作:
[RouteArea("MyArea")]
[Route("Original/{action=index}", Order = 1)]
[Route("Other/{action=index}", Order = 0)]
public class OriginalController : Controller {
...
...
public async Task<ActionResult> Index() { ... }
}
有了上面的内容,我现在可以导航到以下任一 URL,这些 URL 将正确路由到我的 OriginalController
:
的 "Index" 操作
website.com/MyArea/Original
website.com/MyArea/Other
这行得通。但是,我确实定义了另一个操作,它阻塞了属性路由并导致使用传统的默认路由(通过 MapConfig 函数定义)。我的动作签名:
public async Task<ActionResult> Details(int id) {
...
}
这个动作的路由是:website.com/MyArea/Original/Details/123
,也满足默认的约定路由{area}/{controller}/{action}/{id}
。
解决这个问题的方法是更进一步,在操作级别定义路由属性:
[Route("Original/Details/{id:int}")]
[Route("Other/Details/{id:int}")]
public async Task<ActionResult> Details(int id) {
...
}
现在先找到我的路由属性,然后使用常规路由。
在我们的 RouteConfig.cs
文件中,我们有以下默认路由:
routes.MapRoute(
name: "Default",
url: "{controller}/{action}/{id}",
defaults: new { controller = "Original", action = "Index", id = UrlParameter.Optional },
namespaces: new[] { "Path.To.Controllers" }
);
我们的应用程序分为几个不同的 "Areas"。这条特定的路线工作得很好。
我们被要求更改我们的一个 URL,但是底层代码库是相同的。为了避免破坏现有链接,我想设置我的控制器以支持两种不同的路由:
这是原始 URL 的示例:
website.com/MyArea/Original
有了前面提到的 "Default" 路由,这将被定向到 MyArea
区域中的 OriginalController
,并且会触发默认的 Index
动作,因为 none 已指定。
我的目标是设置另一个 URL,它也将自己定向到 OriginalController
。也就是说,
website.com/MyArea/Other
应该路由到 MyArea
区域中的 OriginalController
,并点击默认的 Index
动作。
我已将以下内容添加到 RouteConfig.cs
文件中:
routes.MapRoute(
name: "Other",
url: "Other/{action}/{id}",
defaults: new { controller = "Original", action = "Index", id = UrlParameter.Optional },
namespaces: new[] { "Path.To.Controllers" }
);
我发现 Default
路由配置 总是 用于支持 Other
路由配置,这会导致绑定问题声明“OtherController
找不到”。我怀疑这是因为它们在 url
模板中有一个非常相似的签名,但我不完全确定如何解决这个问题。
我知道还有一个 Route
属性,我不反对使用它。不幸的是,我没有成功地正确设置。
在研究并尝试了几种不同的组合后,我仍然无法让两个 URL 都路由到一个控制器。
我做错了什么?
我能够在控制器本身上使用 RouteAttribute
获得预期的结果(感谢@Michael 提供的资源并让我再次查看 RouteAttribute),而不是传统的 MapConfig
路由。正如我在上面的问题中所描述的,我在尝试 Route
方法时遇到了困难,因为我收到了 404 错误,指出 "resource could not be found"。
事实证明,上述错误是由于我的属性路由没有以正确的顺序连接,这迫使在我的路由属性上使用常规路由(例如默认 MapConfig)。
我偶然发现 this SO post 其中指出:
You are probably combining convention based routing with attribute routing, and you should register your areas after you map the attribute routes.
The line
AreaRegistration.RegisterAllAreas();
should be called AFTER this line:
routes.MapMvcAttributeRoutes();
使用区域时,必须在注册属性路由后注册这些区域。我最初是在 Globas.asax.cs
的 Application_Start
方法中注册我的区域,该方法在 RouteConfig.RegisterRoutes
之前调用。我将此注册移动到 RouteConfig.cs
文件中 MapMvcAttributeRoutes
调用的正下方,这允许控制器上的以下路由属性按预期工作:
[RouteArea("MyArea")]
[Route("Original/{action=index}", Order = 1)]
[Route("Other/{action=index}", Order = 0)]
public class OriginalController : Controller {
...
...
public async Task<ActionResult> Index() { ... }
}
有了上面的内容,我现在可以导航到以下任一 URL,这些 URL 将正确路由到我的 OriginalController
:
website.com/MyArea/Original
website.com/MyArea/Other
这行得通。但是,我确实定义了另一个操作,它阻塞了属性路由并导致使用传统的默认路由(通过 MapConfig 函数定义)。我的动作签名:
public async Task<ActionResult> Details(int id) {
...
}
这个动作的路由是:website.com/MyArea/Original/Details/123
,也满足默认的约定路由{area}/{controller}/{action}/{id}
。
解决这个问题的方法是更进一步,在操作级别定义路由属性:
[Route("Original/Details/{id:int}")]
[Route("Other/Details/{id:int}")]
public async Task<ActionResult> Details(int id) {
...
}
现在先找到我的路由属性,然后使用常规路由。