【问题标题】:Url routing in Post Actions not working properlyPost Actions 中的 URL 路由无法正常工作
【发布时间】:2012-07-28 02:29:49
【问题描述】:

在我的应用程序中,我有一个区域 (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 = Notes,Id = AddNote。 这是路由调试器的输出:

匹配 |网址 |默认值 |约束

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

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

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

有什么建议吗?

【问题讨论】:

    标签: asp.net-mvc-3 url-routing


    【解决方案1】:

    如果您的 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 操作,因为它只是尝试根据 incoming URL 匹配标记:

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

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

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

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

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

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

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

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

    【讨论】:

    • 1.不幸的是,我们在默认控制器(XYZController)中有一些发布操作
    • 2.真正的问题是为什么它在发布期间没有在第一个路由定义中应用正确的约束,而在 Get 请求中应用相同的约束
    • 非常感谢,这是一个非常好的解释..关于你的第一个选项,我不想限制动作名称,因为这里的动作名称非常笼统..第二个效果很好默认控制器中的我的操作具有整数参数。它是一个很好且快速的解决方案,但是将来如果我添加一些带有字符串参数的操作,那么我需要再次更改...所以我想我现在就去使用它,或者我将不得不将我的默认控制器重命名为其他名称,然后使用路由隐藏控制器名称..再次感谢您节省宝贵的时间
    猜你喜欢
    • 1970-01-01
    • 2016-10-17
    • 2016-11-26
    • 2014-12-05
    • 2018-01-17
    • 2017-10-15
    • 1970-01-01
    相关资源
    最近更新 更多