了解 MVC 中的 [HttpPost]、[HttpGet] 和复杂 Action 方法参数

15

我对MVC设计模式和框架非常陌生,同时我也不是非常精通ASP.NET Forms的基础知识。然而,我了解Web开发和HTTP Post和GET的基础知识。

现在,我一直在学习一些MVC教程,我认为我已经很好地掌握了MVC模式的工作原理以及“路由引擎”的工作方式。但突然间,我看到了一段代码,它看起来像下面这样:

public class HomeController : Controller
{
    public ActionResult Index()
    {
        return View(new MyViewModel());
    }

    [HttpPost]
    public ActionResult Index(MyViewModel model)
    {
        return Content("Thanks", "text/html");
    }
}

我看到这里有几个问题:

  • 我理解路由引擎的作用是基于URL将控制权传递给特定的ActionMethod,通常URL基本上是Controller/ActionMethod/Id类型,其中action method的参数是原始类型。在上面的示例中,如何调用“public ActionResult Index(MyViewModel model)”方法需要什么样的URL?

由于MyViewModel是一个复杂类型,你不能将它作为URL的一部分传递。那么怎么调用呢?

  • 为什么第二个方法装饰有[HttpPost],而第一个方法不需要任何属性?是否有关于何时使用[HttpPost]属性和何时不使用的指导方针?

我认为我在这个拼图中缺少了一个重要的部分,两个问题都有相互关联。然而,需要一些帮助来理解它们之间的关系。

3个回答

23
[HttpPost]属性告诉路由引擎将任何POST请求发送到该操作方法,而不是其他方法。这是一种重载方式。

为什么第二个方法要添加[HttpPost]而第一个方法不需要任何属性?

默认情况下,方法的默认属性是[HttpGet]。因此,不需要任何属性。

是否有关于何时使用[Http]属性和何时不使用的指南?

理想情况下,应该在每个方法上使用属性,以避免混淆。随着您对工作原理的熟悉程度越来越高,通常会采用捷径(与其他所有内容一样),并在知道它们不必要时省略它们。

由于MyViewModel是复杂类型,因此无法将其作为URL的一部分传递。如何调用它?

数据将从请求正文中的数据转换为模型。这可以是JSON对象或表单数据。(有一些技巧可以从URL初始化对象,但它们可能有点复杂和高级。)

2
我喜欢这个答案,因为它直接回答了问题,并纠正了一个误解,即复杂对象不能通过URL传递。.NET的模型绑定非常强大!以下是@krillgar所说的它可能变得复杂(即奇怪!)的一个很好的例子http://haacked.com/archive/2008/10/23/model-binding-to-a-list.aspx/ - Vassi
很好的解释。但是,如果我们不在上面的代码中使用 [HttpPost],那么这是否无所谓呢? - Anti Mafia
@AntiMafia 我不确定你的意思。[HttpGet] 是唯一可选的,因为GET是默认的HTTP方法。任何时候,如果你想要进行POST操作,你需要使用该属性装饰该动作。 - krillgar
@krillgar 基于上面的代码,如果我不使用 [HttpPost] 会怎样?这样好吗?程序能正常运行吗? - Anti Mafia
不行。如果你要向服务器发送信息,你需要使用 [HttpPost] - krillgar
这里的“路由引擎”是什么? - carloswm85

3
通常,复杂对象会通过支持它的动词例如POST和PUT在HTTP正文中传递。该正文内容必须通过模型绑定验证。这基本上意味着如果是带有Content-Type: application/json的POST请求,则必须将其从JSON反序列化为MyViewModel。如果内容为XML,则必须将其反序列化为XML。
一般惯例是首先放置所有可以在URL路径、查询和标头中找到的原始数据类型,然后是一个来自POST(或PUT)正文的复杂类型。我认为,可能将复杂类型放在其他地方,但那样就会涉及类型转换器和自定义属性,如果你是初学者,最好不要尝试。
“[HttpPost]”向路由引擎表明此方法重载仅通过HTTP POST可用。在这种情况下,尝试使用带有主体的PUT /home/index将失败并显示404未找到。Index()的无参数版本不需要它,因为它可以使用任何HTTP动词,包括GET、POST和PUT。

1

最佳实践 - 请求处理

在控制器中,最好只使用那些将被视图或JSON服务的公共方法。对于控制器中的所有公共方法,最好使用[HttpGet][HttpPost]标记它们,或者使用其他类型的标记,但我不会涉及到它们,因为它们更多是边缘情况。

这些Http属性限制了该方法仅服务于特定类型的请求。虽然默认值是[HttpGet],但我发现在某些情况下不标记[HttpGet]可能会导致命名冲突时出现意外行为。

最佳实践 - PRG

Post-Redirect-Get是一种设计模式,它基本上规定了每次您将发送来自POST请求的响应时,都应该重定向到GET以发送响应。这可以防止许多情况,包括如果使用了回退按钮,则不要再次发布

重定向通常采用[HttpPost] ActionResult并使用return RedirectToAction("MyHttpGetAction");

发布复杂模型

有多种方式可以发送复杂模型。主要区别在于,如果您使用GET请求,则在URL中,如果使用POST请求,则在请求标头中。如果使用ajax,则差异变得模糊,因为您几乎总是将其发送到正文中。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接