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.csApplication_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) {
    ...
}

现在先找到我的路由属性,然后使用常规路由。