0

在我的应用程序中,我有一个区域(XYZ),其中有一个控制器(XYZController)和该区域内的一堆其他控制器。XYZController 具有索引、查看、创建、编辑等一般操作。与某些特定功能相关的更具体的操作在相应的控制器中相应排列。

为了避免 URL 具有如下结构:app/XYZ(area)/XYZ(Controller)/Create,我在 Area 路由注册文件中添加了如下路由。

context.MapRoute(
                  "XYZ_AreaDefaultControllerActions",
                  "XYZ/{action}/{id}",
                  new { controller = "XYZ", id = UrlParameter.Optional },
                  new { controller = "XYZ" },
                  new string[] { "App.Web.Areas.XYZ.Controllers.*" } 
              );

context.MapRoute(
                "XYZ_default",
                "XYZ/{controller}/{action}/{id}",
                new { controller = "XYZ", action = "Index", id = UrlParameter.Optional}
        );

此映射将 url:app/XYZ/Create 路由到 area = XYZ、Controller = XYZ 和 Action = Create,这是正确的,也是我想要做的,但会弄乱其他一些 Post 操作的路由。

考虑到这一点,我有另一个名为 Notes 控制器的控制器,它有一些 Post 操作。

当请求是 HTTP Get 并且路由调试器的输出显示第二个路由定义匹配而第一个不匹配时,URL 为 /app/XYZ/Notes/List/id 的操作被正确路由。

当我使用带有 url /App/XYZ/Notes/AddNote 的操作 AddNote 向同一个控制器发布帖子时,第一个路由定义根据路由调试器匹配,因此找不到该操作,因为它需要 Controller = XYZ, Action = 注释,ID = 添加注释。这是路由调试器的输出:

比赛 | 网址 | 默认值 | 约束

  1. 真 | XYZ/{action}/{id} | 控制器 = XYZ,ID = | 控制器 = XYZ

  2. 真 | XYZ/{控制器}/{动作}/{id} | 控制器 = XYZ,动作 = 索引,id = |(null)

问题是,在 Post 的情况下,第一条路线的约束似乎对它的限制不够,而在 Get 它应用了约束。

有什么建议吗?这里出了什么问题?

4

1 回答 1

0

如果您的 XYZController 没有任何 POST 操作,您可以添加这样的约束以防止 POST 请求匹配您的第一个路由:

context.MapRoute("XYZ_AreaDefaultControllerActions",
    "XYZ/{action}/{id}",
    new { controller = "XYZ", id = UrlParameter.Optional },
    new { controller = "XYZ", httpMethod = new HttpMethodConstraint("GET") },
    new string[] { "App.Web.Areas.XYZ.Controllers.*" }
);

更新

由于您在 XYZController 中有发布操作,就像您提到的那样,上述路由约束对您不起作用。

这里的问题是您有一个与您所在区域同名的控制器。这就是为什么 MVC 将第一个路由匹配到您的 notes 控制器 POST 操作,因为它只是尝试根据传入的URL 匹配令牌:

  • /XYZ - 从字面上匹配您的第一条路线的第一段
  • /Notes - 这将被填充到您的 {action} 段中
  • /AddNote - 这将被填充到您的 {id} 段中

给定您的第一个路由,{ controller = "XYZ" }约束没有任何区别,因为 MVC 正在尝试将入站 URL 路由到控制器 + 操作 + 参数。MVC 不知道它来自哪个控制器,它试图匹配将处理 URL 请求的控制器和操作。

一种解决方案是向您的第一条路线添加动作约束,但这仅在 XYZController 中的动作名称与您的笔记控制器中的任何 POST 动作名称不匹配时才有效:

new { controller = "XYZ", action = "XYZAction1|XYZAction2|XYZActionN" },

对于传入路由,仅当操作是约束中的管道分隔名称之一时,它才会匹配第一个路由。

另一种选择是使用 regex 限制您的 {id} 路线段。如果您的 id 是字符串,这可能不是一个选项。但是,如果您的 id 始终是数字,您可以将第一条路由限制为仅在它们为数字时将路由段与 {id} 标记匹配。这样,“AddNote”将不匹配您的第一条路线的 {id} 段,因为它不是数字:

new { controller = "XYZ", id = @"\d+" },

要回答您的第二条评论,这适用于 GET 的原因是因为您的第二条路线有一个额外的路线段。带有 id 的 GETS 与第一条路线不匹配,因为它们有 4 个令牌,而不是 3 个。

于 2012-07-30T13:03:10.903 回答