Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

ASP.NET MVC: How does a controller distingush between parameters in the URL and sent by POST

I would like to better understand how a controler method knows when a parameter it recives should be retrived from the post data or the url.

Take the following example:

URL: /ModelController/Method/itemID 
// Where itemID is the id (int) of the item in the database
POST: objectOrArray: {JSON Object/Array}

The controller would look something like this:

[HttpPost]
public ActionResult InputResources(int? id, Object objectOrArray)

Now, somehow the method is smart enough to look for the first parameter, the id, in the site URL and the Object in the HTTPPost.

Whilst this works, I don't know why, and as a result I sometimes run into unpredictable and erratic behaviour. For example, I seem to have found (although I am not 100% sure) that removing the ? from int? id makes the controller method inmediately assume it should look for the id in the HTTPPost and not the URL.

So I would like to clarify the following points:

What exactly is it that tells the method where to look for the data? (The [HttpPost] attribute preciding the method?)

Do naming conventions come into play? (for example removint the ? or not using id as the variable name?)

Does the order in which the variables are placed have an inpact? (ie placing the Object before the id)

I know I can more or less figure out some of this stuff by trial and error, but I would like a qualified explanation rather than to continiue to work of assumption based on observation.

Thank you

Chopo

like image 516
Chopo87 Avatar asked Apr 26 '13 09:04

Chopo87


1 Answers

Take a look at the default route from Global.asax:

routes.MapRoute(
    "Default",                                            
    "{controller}/{action}/{id}",                     
    new { controller = "Home", action = "Index", id = UrlParameter.Optional }
);

The first thing that MVC will try to do is map your method parameters to values in the POST. If it doesn't find a match, it will cascade through other possibilities, including the route values.

Here's the order the model binder uses:

  1. Previously bound action parameters, when the action is a child action
  2. Form fields (Request.Form)
  3. The property values in the JSON Request body (Request.InputStream), but only when the request is an AJAX request
  4. Route data (RouteData.Values)
  5. Querystring parameters (Request.QueryString)
  6. Posted files (Request.Files)

The reason you're seeing the behaviour you describe is because POST data comes before route values. It seems that MVC can't bind a nullable int to a POST value, so it skips over it and keeps going until it reaches the RouteData mapping, at which point, it finds a match and gets the value from the route. When you make the parameter non-nullable, it is suddenly able to bind it to the POST value, which has higher precedence than RouteData, so it does.

Source: http://msdn.microsoft.com/en-us/magazine/hh781022.aspx

like image 58
Ant P Avatar answered Sep 22 '22 13:09

Ant P