开发者

Posting JSON to Controller

I've got this in my controller:

[开发者_StackOverflowHttpPost]
public void UpdateLanguagePreference(string languageTag) {
 if (string.IsNullOrEmpty(languageTag)) {
  throw new ArgumentNullException("languageTag");
 }
 ...
}

And have this jQuery code POSTing to the controller:

jQuery.ajax({
  type: 'POST',
  url: '/Config/UpdateLanguagePreference',
  contentType: 'application/json; charset=utf-8',
  data: '{ "languageTag": "' + selectedLanguage + '" }'
});

When I try to the code, however, I get the error:

Server Error in '/' Application.
Value cannot be null.
Parameter name: languageTag

What's the problem? Isn't this how to POST JSON to an MVC Controller? I can examine the POST using Fiddler and see that the request is correct. For some reason, UpdateLanguagePreference() is getting a null or empty string.


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.


When you give jQuery's $.ajax() function a data variable in the form of a javascript object, it actually translates it to a series of key/value pairs and sends it to the server in that manner. When you send the stringified json object, it's not in that form and the standard model binder in mvc/mvc2 won't cut it.

If you want to send post data in such a way, then you're very nearly there. You need the JsonValueProviderFactory class found in MVC2 Futures/MVC3 Beta. Take a look at the following links for more info:

http://haacked.com/archive/2010/04/15/sending-json-to-an-asp-net-mvc-action-method-argument.aspx

... there's another link I used when implementing this myself that talked more about bringing the JsonValueProviderFactory class into your app, but I can't find it for the life of me.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜