【问题标题】:Specify HTTP VERB for Url.Action?为 Url.Action 指定 HTTP VERB?
【发布时间】:2014-05-14 05:22:28
【问题描述】:

我正在使用 AttributeRouting:http://attributerouting.net/

如果我有两个具有相同名称的操作,但 GET 的路径与 POST 的路径不同,为什么 Url.Action 会生成与我的 GET 操作匹配的 URL,即使我的操作方法指向到那个是帖子的那个?

我尝试将动词作为

Url.Action("CreateEdit", new { method = "POST" })

但是,这将返回字符串 /enrollments/create,而不是对应于 POST 的 /enrollments/createedit

我不希望这会起作用,但尝试了它,因为某些路由配置使用了这种技术:

Url.Action("CreateEdit", new { HttpMethodConstraint = new HttpMethodConstraint("POST") })

但是这两个都不能解决问题,并且 URL 仍然是我的 GET 路由。

我已经验证我可以发布到/enrollments/createedit 的硬编码 URL,因此 POST 操作确实具有该路由,只是为了排除 POST 操作的默认 [POST] 默认为预期路由的可能性。

问题是我通常避免使用硬编码的 URL 并使用 Url.Action 或 Html.BeginForm(这也表现出同样的问题),以便所有 URL 都派生自操作路由。

以下是我如何定义我的行为:

[GET("create")]
[GET("edit/{id:guid?}")]      
public ActionResult CreateEdit(Guid? id)
...

[POST] //default to "createedit"
public ActionResult CreateEdit()
...

请注意,这个问题不是关于发出实际请求,而是生成路由 url。

你如何向 Url.Action 表明它应该使用来自 [POST] 而不是 GET 的路由。没有采用约束或 HTTP 动词的重载?请注意,Html.BeginForm 在生成操作 URL 属性时会出现同样的问题,这显然是面向 POST 的方法。

如果我将操作路线简化为(尽管以上是我的目标路线),它也不起作用:

[GET("create")]
public ActionResult CreateEdit()
...

[POST("createedit")] //default to "createedit"
public ActionResult CreateEdit()
...

Url.Action("CreateEdit", new { method = "POST" }) 显然返回“/enrollments/create”,因为method = 'POST' 不是为 Url.Action 指定所需路由的正确方法。 有没有办法告诉 Url.Action 或 Html.BeginForm 指定需要 POST 路由? BeginForm 的方法参数影响method="post" html 属性,但仍使用生成的 action 属性错误的/enrollments/create URL。我见过area="Admin" 用于在路由参数中指定区域。是否可以添加一些神奇的属性来指定动词?如果没有,那么显然没有办法始终如一地获得正确的 URL,如果我需要维护所需的路由,我可能需要重命名我的一项操作。我希望有一些路线价值,我可以将 analogous 添加到 new { area = "SomeArea" }method = "POST" 只是我对可行方法的疯狂猜测。

请求管道尊重路由约束,如果它们都是相同的路由,那么它可以正常工作。因此,如果两者都是[POST("creatededit")][GET("create"],那么它会正常工作,因为两者的 URL 是相同的,然后当发出实际请求时,由于 HttpMethodContraint,管道会做出区分。

如果我使用参数来区分路由,它会起作用,但前提是我消除了[GET("create")]

如果 Url.Action 没有已知/支持/记录的方式来获取路由属性,那么答案可能只是 Url.Action 没有任何方法让您告诉它所需的动词。

  • 如果有人问:有没有办法为 Url.Action 指定区域?
  • 答案很简单:Url.Action("SomeAction", new { area ="SomeArea" })
  • 答案不是:弄乱你的路线,这样你就不会在不同的区域有两个同名的操作(或任何其他不能解决问题的事情)。
  • 答案是否定的:您不应该在不同的领域有相同名称的操作。 (这可能是一个有效的观点,但它不会为处于绝对必须为不同区域生成 URL 的情况的其他人创建有用的资源。

我不明白这有什么复杂的。

我不是在问如何发出 POST 请求。我知道该怎么做,但我不打算将 URL 硬编码到我的视图中。这变成了一场维护噩梦。

如果我的老板对国有企业不那么执着,我可以改变我的路线。所以我无法消除 [GET("create")] 路线。

我可以通过像这样重命名一个动作来解决:

[GET("create")]
[GET("edit/{id:guid?}")]      
public ActionResult CreateEdit(Guid? id)
...

[POST("createedit")] 
public ActionResult CreateEditPost()
...

这有点脏,但有效。它仍然没有回答这个问题。

如果有办法为 Url.Action 指定 VERB,我认为答案将是一个有用的资源。也许不像Url.Action("SomeAction", new { area ="SomeArea" }) 那么多人,但它会记录Url.Action 的一个对我来说一直难以捉摸的功能。也许它不支持它。也许我需要深入研究源代码。

【问题讨论】:

  • 在浏览器中单击链接始终是 GET。从浏览器发布的唯一方法是使用 POST 方法提交表单。使用哪个动词不会发布到 URL 本身。
  • Url.Action 可用于 POST 和 GET。 BeginForm 也会出现同样的问题。这是一个 URL 生成问题,而不是请求问题。 BeginForm 使用与 Url.Action 相同的过程来生成操作属性 URL。两者都表现出同样的问题。这不是关于请求,而是关于 URL。
  • “这是一个 URL 生成问题,而不是请求问题”我完全不同意。这可能是因为生成的 URL 与您的 POST 路由不匹配,但 URL 就是 URL。它们本身并没有说明将使用什么动词。这是使用 URL 决定的机制,例如表单与链接。
  • 您的问题没有包含足够的信息,无法在没有假设的情况下有效回答。 Url.Action 生成的 URL 是什么?
  • 我将对您的问题提出一些修改意见,所以我认为我们都在同一页面上。如果您不喜欢它们,请随时回滚。

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


【解决方案1】:

我原来的答案搞砸了。我并没有真正考虑清楚,可能回答得太快了。归结为:

Url.Action 本质上与控制器/动作样式路由相关联。当有两个匹配的操作(一个是 GET 版本,另一个是 POST 的重载)时,URL 应该 相同,因此返回 GET 或真正的第一个版本。看,AttributeRouting 只是通过让您自定义面向外部的 URL 来进行分层,但在内部,Url.Action 只是试图找到一个可以让您到达请求操作的路由。一旦找到匹配项,它就会认为这已经足够好了,尤其是在 MVC5 之前,它应该是这样的。

MVC5 将属性路由作为一等公民引入,但据我所知,这种极端情况(同一操作的 GET 和 POST 版本具有不同的 URL,而您尤其想要 POST 版本)并没有被覆盖了。

也就是说,我看到了一些潜在的解决方法:

  1. 使用不同的操作名称。如果您的 POST 操作名称类似于 CreateEditPost,那么您可以非常轻松地使用 Url.Action("CreateEditPost") 并获得正确的 URL。由于您的路线不受操作名称的直接影响,因此它的名称并不重要。

  2. 使用命名路由。如果你命名你的路由,那么你可以使用Url.RouteUrl 代替并请求你想要的路由。例如:

    [POST("createedit", RouteName = "CreateEditPost")]
    public ActionResult CreateEdit()
    {
        ...
    }
    

    然后:

    @Url.RouteUrl("CreateEditPost")
    

【讨论】:

  • "是的,您可以在 Url.Action 中将方法指定为 post" 这是如何完成的?你在哪里将它传递给 Url.Action? new { method= "POST"} 是正确的方法吗?这只是我的一个疯狂猜测。
  • 感谢您解决这个问题。我确实了解我使用 URL 的上下文很重要,因此它用于 POST 请求。
  • 对不起。我最初的回答非常糟糕。我并没有真正花时间去做我应该做的事情,并做出了我不应该做的假设。请参阅我编辑的答案。
  • 感谢克里斯,我被称为“拒绝”和“一文不值”来达到这一点。很高兴终于来到这里。
猜你喜欢
  • 2017-10-30
  • 1970-01-01
  • 2013-10-22
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-11-07
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多