Posting JSON to Controller Posting JSON to Controller json json

Posting JSON to Controller


Very important caveat, even in MVC3, about the way MVC3 works.

If you pass an object like say:

​{    Test: 'Hi'}

And the receiving class is:

public class MyModel{    public string Test { get; set; }}

With a receiving Controller method like:

[HttpPost]public JsonResult Submit(MyModel model){    . . .

It will work. But if your Controller method has this very minor, seemingly harmless change:

[HttpPost]public JsonResult Submit(MyModel test){    . . .

It will fail. This is because the MVC framework consumes the JSON into a Dictionary as mentioned above, and sees that one of the parameters has the same name, case-insensitive, as one of its keys ("Test"/"test"). It then takes the string value "Hi", assigned to Test, and passes that to this argument "test" even though this is obviously not what the author intended.

What's most problematic about this is that the framework doesn't throw an error trying to assign a string to an arg of type MyModel, which would at least give you a clue about what went wrong. It doesn't see this was the wrong type and fallback to its alternative behavior (that it would have pursued had these arg/properties not matched in name). It simply fails silently and assigns null to your argument, leaving you with no clue as to what's going on.

I've run into this problem repeatedly and finally found the glitch that makes things seem to randomly stop working in MVC... I hope this helps someone else.

Since any reasonable name for this Action argument is a potentially reasonable property name (model, data, etc) and since it's case-insensitive, the safest way to prevent it without writing your own model binder is to standardize on one, crazy, very-unlikely-to-ever-be-a-property-name argument name, like:

[HttpPost]public JsonResult Submit(MyModel _$_$twinkleTwinkleLittleFuckIt){

But if you have the time, fix the ModelBinder/JsonValueProviderFactory so there's 0 risk instead of that one weird bug in a decade no one can ever get to the bottom of.


hmm....

I do it

 $.post(target,         {             "ProblemId": id,             "Status": update         }, ProcessPostResult);

with

public class ProblemReportUpdate    {        public int ProblemId { get; set; }        public string Status { get; set; }    }

and

 [HttpPost] public ActionResult UpdateProblemReport(ProblemReportUpdate update)

the target is set by

var target = '<%=Url.Action("UpdateProblemReport", "ProblemReport") %>


You are posting a string and not a JSONified object.

data: '{ "languageTag": "' + selectedLanguage + '" }'

should be

data: { "languageTag": selectedLanguage }

And make sure selectedLanguage is defined within the scope of your ajax call.