为Url.Action指定HTTP VERB?

时间:2014-05-13 18:55:18

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

我正在使用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") })

然而,这些都无法解决问题,而且网址仍然是我的GET路线。

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

问题是我通常会避免使用硬编码的网址,并使用Url.Action或Html.BeginForm(也会出现同样的问题),以便所有网址都来自行动路线。

以下是我定义行动的方式:

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

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

请注意,此问题与提出实际请求无关,而是生成路由网址。

如何向Url.Action表明它应该使用来自[POST]而不是GET的路线。没有带有约束或HTTP Verb的重载?请注意,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网址生成。我看到area="Admin"用于指定路线参数中的区域。是否有一些魔法属性可以添加来指定动词?如果没有,那么显然没有办法一致地获得正确的URL,如果我需要维护所需的路由,我可能需要重命名我的一个动作。我希望有一些路线值我可以将类似的添加到new { area = "SomeArea" }method = "POST"只是我对可能有效的猜测。

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

如果我使用参数使路线不同,那么只有当我消除[GET("create")]

时它才有效

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

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

我不明白这是多么复杂。

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

如果我的老板不在SOE上,我可以改变我的路线。所以我无法消除[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的一个功能,对我来说这是难以捉摸的。也许它不支持它。也许我需要深入研究源代码。

1 个答案:

答案 0 :(得分:2)

我在原来的答案中蠢蠢欲动。我并没有真正思考它,而且可能回答得太快了。以下是它归结为:

Url.Action与控制器/动作样式路由非常相关。如果有两个匹配的操作(重载,其中一个是GET版本而另一个是POST),则URL 应该相同,因此返回GET或第一个版本。通过让您自定义面向外部的URL,参见AttributeRouting,而在内部,Url.Action只是试图找到一条路径,让您进入所请求的操作。一旦找到匹配,它就会假定它已经足够好了,特别是在MVC5之前,它应该是。

MVC5引入属性路由作为一等公民,但从我所见,这个边缘情况(同一行为的GET和POST版本有不同的URL,你特别想要POST版本)没有被覆盖。

那就是说,我看到了几个可能的解决方法:

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

  2. 使用命名路由。如果您为路线命名,则可以使用Url.RouteUrl代替您想要的路线。例如:

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

    然后:

    @Url.RouteUrl("CreateEditPost")