MVC [HttpPost/HttpGet] for Action

154,457

Solution 1

Let's say you have a Login action which provides the user with a login screen, then receives the user name and password back after the user submits the form:

public ActionResult Login() {
    return View();
}

public ActionResult Login(string userName, string password) {
    // do login stuff
    return View();
}

MVC isn't being given clear instructions on which action is which, even though we can tell by looking at it. If you add [HttpGet] to the first action and [HttpPost] to the section action, MVC clearly knows which action is which.

Why? See Request Methods. Long and short: When a user views a page, that's a GET request and when a user submits a form, that's usually a POST request. HttpGet and HttpPost just restrict the action to the applicable request type.

[HttpGet]
public ActionResult Login() {
    return View();
}

[HttpPost]
public ActionResult Login(string userName, string password) {
    // do login stuff
    return View();
}

You can also combine the request method attributes if your action serves requests from multiple verbs:

[AcceptVerbs(HttpVerbs.Get | HttpVerbs.Post)].

Solution 2

You don't need to specify both at the same time, unless you're specifically restricting the other verbs (i.e. you don't want PUT or DELETE, etc).

Contrary to some of the comments, I was also unable to use both Attributes [HttpGet, HttpPost] at the same time, but was able to specify both verbs instead.

Actions

    private ActionResult testResult(int id)
    {
        return Json(new {
                            // user input
                            input = id,
                            // just so there's different content in the response
                            when = DateTime.Now,
                            // type of request
                            req = this.Request.HttpMethod,
                            // differentiate calls in response, for matching up
                            call = new StackTrace().GetFrame(1).GetMethod().Name
                        },
                        JsonRequestBehavior.AllowGet);
    }
    public ActionResult Test(int id)
    {
        return testResult(id);
    }
    [HttpGet]
    public ActionResult TestGetOnly(int id)
    {
        return testResult(id);
    }
    [HttpPost]
    public ActionResult TestPostOnly(int id)
    {
        return testResult(id);
    }
    [HttpPost, HttpGet]
    public ActionResult TestBoth(int id)
    {
        return testResult(id);
    }
    [AcceptVerbs(HttpVerbs.Get | HttpVerbs.Post)]
    public ActionResult TestVerbs(int id)
    {
        return testResult(id);
    }

Results

via POSTMAN, formatting by markdowntables

| Method    | URL                   | Response                                                                                  |
|--------   |---------------------- |----------------------------------------------------------------------------------------   |
| GET       | /ctrl/test/5          | { "input": 5, "when": "/Date(1408041216116)/", "req": "GET", "call": "Test" }             |
| POST      | /ctrl/test/5          | { "input": 5, "when": "/Date(1408041227561)/", "req": "POST", "call": "Test" }            |
| PUT       | /ctrl/test/5          | { "input": 5, "when": "/Date(1408041252646)/", "req": "PUT", "call": "Test" }             |
| GET       | /ctrl/testgetonly/5   | { "input": 5, "when": "/Date(1408041335907)/", "req": "GET", "call": "TestGetOnly" }      |
| POST      | /ctrl/testgetonly/5   | 404                                                                                       |
| PUT       | /ctrl/testgetonly/5   | 404                                                                                       |
| GET       | /ctrl/TestPostOnly/5  | 404                                                                                       |
| POST      | /ctrl/TestPostOnly/5  | { "input": 5, "when": "/Date(1408041464096)/", "req": "POST", "call": "TestPostOnly" }    |
| PUT       | /ctrl/TestPostOnly/5  | 404                                                                                       |
| GET       | /ctrl/TestBoth/5      | 404                                                                                       |
| POST      | /ctrl/TestBoth/5      | 404                                                                                       |
| PUT       | /ctrl/TestBoth/5      | 404                                                                                       |
| GET       | /ctrl/TestVerbs/5     | { "input": 5, "when": "/Date(1408041709606)/", "req": "GET", "call": "TestVerbs" }        |
| POST      | /ctrl/TestVerbs/5     | { "input": 5, "when": "/Date(1408041831549)/", "req": "POST", "call": "TestVerbs" }       |
| PUT       | /ctrl/TestVerbs/5     | 404                                                                                       |

Solution 3

In Mvc 4 you can use AcceptVerbsAttribute, I think this is a very clean solution

[AcceptVerbs(WebRequestMethods.Http.Get, WebRequestMethods.Http.Post)]
public IHttpActionResult Login()
{
   // Login logic
}

Solution 4

You cant combine this to attributes.

But you can put both on one action method but you can encapsulate your logic into a other method and call this method from both actions.

The ActionName Attribute allows to have 2 ActionMethods with the same name.

[HttpGet]
public ActionResult MyMethod()
{
    return MyMethodHandler();
}

[HttpPost]
[ActionName("MyMethod")]
public ActionResult MyMethodPost()
{
    return MyMethodHandler();
}

private ActionResult MyMethodHandler()
{
    // handle the get or post request
    return View("MyMethod");
}
Share:
154,457
Nate Pet
Author by

Nate Pet

Updated on July 09, 2022

Comments

  • Nate Pet
    Nate Pet almost 2 years

    I am using MVC C#.

    Can somebody give an example on why one would use

    [HttpPost/HttpGet] 
    

    for an Action. How can an active have both - what is the practical use?

  • Nate Pet
    Nate Pet over 11 years
    Thanks for your answer. I understand what you are saying and have used it accordingly. From some reading online, I was under the impression that we can use [HttpGet] and [HttpPost] for the same action (not seperated)
  • Admin
    Admin about 11 years
    Not sure what "You cant combine this to attributes." means, but you can combine attributes, as shown in another answer.
  • Marcin
    Marcin almost 11 years
    I tried to add [HttpGet, HttpPost] to one action, but this is not working only first attribute working, so for me this answer is correct.
  • angularsen
    angularsen over 10 years
    [AcceptVerbs(HttpVerbs.Post|HttpVerbs.Get)] works. Just tried it. However, using [HttpGet] and [HttpPost] on same action only seems to work for the first verb.
  • angularsen
    angularsen over 10 years
    Just tried on MVC4. [HttpGet][HttpPost] does not work, that only accepts GET requests (or whichever verb is written first). However, [AcceptVerbs(HttpVerbs.Get | HttpVerbs.Post)] does work well.
  • Reaksmey
    Reaksmey over 10 years
    @AndreasLarsen: Maybe consider posting a question about that specifically so MS can see it. I'll edit my answer if I can get confirmation it's intentionally.
  • Paul
    Paul over 9 years
    I can confirm what AndreasLarsen reported. You must use AcceptVerbs to have 2+ verbs on the method.
  • Co7e
    Co7e over 9 years
    @Kivin I've tested [HttpGet, HttpPost] in MVC5 and it does not work for both verbs. drzaus's answer also confirms that it doesn't work. [AcceptVerbs(HttpVerbs.Get | HttpVerbs.Post)] does work however.
  • Phiber
    Phiber about 8 years
    Good example. Thank you
  • Aleksander Bethke
    Aleksander Bethke over 7 years
    Thanks for AcceptVerbs solution. Somehow this works while when I specify [HttpGet] and [HttpOptions] does not
  • CubanTurin
    CubanTurin over 4 years
    It is not incorrect because it works yet it is unnecessary as httppost and httpget can be combined using the acceptvebs as shown before