在同一个控制器中使用相同的操作名称和GET、POST方法

92

为什么这是不正确的?

{
    public class HomeController : Controller
    {

        [HttpGet]
        public ActionResult Index()
        {
            Some Code--Some Code---Some Code
            return View();
        }

        [HttpPost]
        public ActionResult Index()
        {
            Some Code--Some Code---Some Code
            return View();
        }

    }

当控制器被“获取”时,我该如何让它回答一个问题,当它被“发布”时,又该如何回答另外一个问题?

8个回答

203

由于您不能使用相同名称和签名的两个方法,因此必须使用ActionName属性:

[HttpGet]
public ActionResult Index()
{
  // your code
  return View();
}

[HttpPost]
[ActionName("Index")]
public ActionResult IndexPost()
{
  // your code
  return View();
}

也请参见“方法如何成为操作”


我知道现在问有点晚了,但是是否可能拥有两个不同的HttpPost操作方法,它们具有相同的名称但接受不同的参数。我指的是需要对已经定义了一个HttpPost方法的创建方法应用过滤器的情况。 - Vini
是的,这是可能的,因为它是一个有效的 .Net 方法签名。这些方法是重载的(方法重载)。 - nwolisa

42

虽然ASP.NET MVC允许您拥有两个具有相同名称的操作,但.NET不允许您拥有具有相同签名(即相同的名称和参数)的两个方法。

您需要为这些方法命名不同的名称,并使用ActionName属性告诉ASP.NET MVC它们实际上是相同的操作。

话虽如此,如果您正在谈论GET和POST,则此问题可能会消失,因为POST操作将比GET操作接受更多的参数,因此可以区分它们。

因此,您需要:

[HttpGet]
public ActionResult ActionName() {...}

[HttpPost, ActionName("ActionName")]
public ActionResult ActionNamePost() {...}

或者,

[HttpGet]
public ActionResult ActionName() {...}

[HttpPost]
public ActionResult ActionName(string aParameter) {...}

1
例如,对于GET和POST的删除操作都需要一个ID。GET用于查看数据,POST用于删除数据。在这种情况下,我需要使用ActionName。 - Default

17

我喜欢接受表单提交,即使我并不需要它。对我来说,这只是一种正确的感觉,因为你应该会提交某些内容

public class HomeController : Controller
{
    public ActionResult Index()
    {
        //Code...
        return View();
    }

    [HttpPost]
    public ActionResult Index(FormCollection form)
    {
        //Code...
        return View();
    }
}

2
唯一的问题是,即使使用[AllowHtml]等也会触发该可恶的HttpRequestValidationException。这并不是一个坏的异常,但它的实现方式以及何时触发(特别是在某个区域触发时)是不必要地不透明。 - Ted

5

回答你的具体问题,一个类中不能有两个方法使用相同的名称和相同的参数;使用HttpGet和HttpPost属性不能区分这些方法。

为了解决这个问题,我通常会在提交表单时加入视图模型:

public class HomeController : Controller
{
    [HttpGet]
    public ActionResult Index()
    {
        Some Code--Some Code---Some Code
        return View();
    }

    [HttpPost]
    public ActionResult Index(formViewModel model)
    {
        do work on model --
        return View();
    }

}

5
你已经收到了这个问题的好回答,但我想补充一下。你可以使用一种方法并根据请求类型处理请求:
public ActionResult Index()
{
    if("GET"==this.HttpContext.Request.RequestType)
    {
        Some Code--Some Code---Some Code for GET
    }
    else if("POST"==this.HttpContext.Request.RequestType)
    {
        Some Code--Some Code---Some Code for POST
    }
    else
    {
        //exception
    }

    return View();
}

2

不能使用相同的名称和参数执行多个操作

    [HttpGet]
    public ActionResult Index()
    {
        return View();
    }
    [HttpPost]
    public ActionResult Index(int id)
    {
        return View();
    }

尽管 int id 没有被使用


2

您不能使用相同的名称进行多个操作。您可以向一个方法添加参数,这将是有效的。例如:

    public ActionResult Index(int i)
    {
        Some Code--Some Code---Some Code
        return View();
    }

有几种方法可以根据请求动词实现不同的操作。我最喜欢的,也是我认为最容易实现的方法是使用AttributeRouting包。安装后,只需将属性添加到您的方法中,如下所示:

  [GET("Resources")]
  public ActionResult Index()
  {
      return View();
  }

  [POST("Resources")]
  public ActionResult Create()
  {
      return RedirectToAction("Index");
  }

在上面的示例中,这些方法有不同的名称,但在两种情况下的操作名称都是“Resources”。唯一的区别是请求动词。
可以使用NuGet安装此包,如下所示:
PM> Install-Package AttributeRouting
如果您不想依赖AttributeRouting包,则可以通过编写自定义操作选择器属性来实现此目的。

0
今天我在查找有关同一问题的一些资源时,我得到了一个非常有趣的例子。 可以通过GET和POST协议调用相同的方法,但是您需要像这样重载参数:
@using (Ajax.BeginForm("Index", "MyController", ajaxOptions, new { @id = "form-consulta" }))
{
//code
}

操作:

[ActionName("Index")]
public async Task<ActionResult> IndexAsync(MyModel model)
{
//code
}

默认情况下,没有明确协议的方法是GET,但在这种情况下,有一个声明的参数允许该方法像POST一样工作。

当执行GET时,参数无关紧要,但当执行POST时,您的请求需要该参数。


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