15

I am very very new to MVC the design-pattern and also the Framework. I am also not extremely well- versed in fundamentals of ASP.NET Forms. However, I do understand the basics of web development and HTTP Post and GET as well.

Now, I have been going through some MVC tutorials and I though I was getting a good hold of how MVC the pattern works and also how "Routing Engine" works. Then suddenly I came across a code which looks like folloing:

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

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

I have few questions looking at it:

  • My understanding of routing engine was that the control is passed to a particular ActionMethod based on URL and normally URL are basically Controller/ActionMethod/Id kind where paramter to action menthod are rather Primitive types. In this example above what kind of URL would it take to call "

public ActionResult Index(MyViewModel model)?"

Since NyViewModel is a complex type, you can not pass it as part of URL. How can you call it?

  • Why is this second method adorned with [HttpPost] when the first method does not require any attributes? Are there any guidelines on when to use [Http] attributes and when not?

I think I am missing a big pice in the puzzle and both the questions are interrelated. However, need some help in making sense with the relationship

3 Answers 3

23

The [HttpPost] attribute tells the routing engine to send any POST requests to that action method to the one method over the other. This is a type of overloading.

Why is this second method adorned with [HttpPost] when the first method does not require any attributes?

The default for a method is [HttpGet]. Because of that, no attribute is needed.

Are there any guidelines on when to use [Http] attributes and when not?

Ideally, attributes should be on every method, in order to avoid confusion. As you get more familiar with how things are working, you will often take shortcuts (as with everything else), and omit them when you know that they are not necessary.

Since MyViewModel is a complex type, you can not pass it as part of URL. How can you call it?

The data will be turned into the model from the data in the body of the request. This can come either as a JSON object, or as Form data. (There are tricks to get the object initialized from the URL, but they can be a little complicated and advanced.)

6
  • 2
    I like this answer because it directly answers the questions and also corrects the misconception that complex objects can't be passed in via URL. .NET's model binding is really quite robust! Here's a good example of why @krillgar says it can get complicated (I.E. weird!) haacked.com/archive/2008/10/23/model-binding-to-a-list.aspx
    – Vassi
    Commented Feb 28, 2015 at 3:46
  • Nice explanation. But, so it doesn't matter if we don't use the [HttpPost] on the code above?
    – Anti Mafia
    Commented Jan 8, 2017 at 12:33
  • @AntiMafia I'm not sure what you mean. [HttpGet] is the only one that is optional because GET is the default HTTP method. Any time you want to do a POST, you need to decorate the action with the attribute.
    – krillgar
    Commented Jan 8, 2017 at 14:43
  • @krillgar based on the code above, how if i don't use [HttpPost]? Is it good? Can program running correctly?
    – Anti Mafia
    Commented Jan 8, 2017 at 15:06
  • No. If you're sending information to the server, you need to use [HttpPost].
    – krillgar
    Commented Jan 9, 2017 at 12:07
3

Generally, complex objects are passed in the HTTP body with verbs that support it such as POST and PUT. The body content must pass Model Binding validation. That basically means that if it's a POST request with Content-Type: application/json, it must deserialize from JSON into MyViewModel. If the content is XML, it must deserialize as XML.

General convention is to have all the primitive types that can be found in the URL path, query, and headers first, then one complex type from the POST (or PUT) body after that. I believe it's possible to put complex types elsewhere, but then you're getting into type converters and custom attributes which you should probably hold off on if you're a beginner.

Why is this second method adorned with [HttpPost] when the first method does not require any attributes? Are there any guidelines on when to use [Http] attributes and when not?

"[HttpPost]" is telling the routing engine that this method overload is only available via HTTP POST. Attempting to PUT /home/index with a body will fail with 404 Not Found, in this case. The parameter-free version of Index() doesn't require it because it can work with any HTTP verb, including GET, POST, and PUT.

1

Best Practice - Request handling

It is best practice to only use public methods in your controller which are going to be serviced either with a view or with json. For all public methods in your controller, it is best practice to either mark them with an [HttpGet] or an [HttpPost], or one of the other types which I wont cover as they are more edge case scenario.

These Http attributes restrict the method to only servicing those specific types of requests. While the default is [HttpGet], I have found that not marking [HttpGet] in all scenarios can at times lead to unexpected behavior when there are naming conflicts.

Best Practice - PRG

Post-Redirect-Get is a design pattern which essentially stipulates that any time you are going to be sending a response which came from a POST request, you should redirect to a get in order to send the response. This protects from a number of scenarios, including not posting again if the back button is used.

The redirect usually comes in the form of the [HttpPost] ActionResult using return RedirectToAction("MyHttpGetAction");.

Posting complex models

There are multiple ways which you can send a complex model. The main difference is that if you are using a GET request it is in the url, and if you are using a POST request it is in the request headers. If you use ajax then the difference becomes blurred as you will almost always send it in the body.

Not the answer you're looking for? Browse other questions tagged or ask your own question.