james lewis
james lewis

Reputation: 2532

MVC 3 trying to send JSON object from view to model

I'm currently trying to post a JSON object from my view to my controller in an MVC 3 app and I'm expecting the data from the request to bind to the model parameter of my controller action. However, when I inspect the HTTP POST request, it looks like the data is being passed as a query string and I'm unsure why (pretty new to all this).

Here's my POST request:

    $.ajax({
        type: 'POST',
        url: "Test/Add",
        data: { Name: name, Age: age },
        success: function (data) {
            console.log("success");
        },
        error: function (xhr, data, message) {
            console.log(data + ": " + message);
        },
        dataType: "json"
    });

Here's the code from my Controller followed by the code for the model I'm trying to bind to:

    [HttpPost]
    public ActionResult Add(PersonModel person)
    {
        System.Threading.Thread.Sleep(1000);

        return View();
    }

    // person model:
    public class Person {

        public string Name {get;set;}
        public int Age {get;set;}

    }

This is the request from fiddler - I've highlighted the parts I'm unsure about:

enter image description here

I thought content type would be "application/json" and that the data wouldn't look like a query string - I thought it would look something like this:

{
    Name: "James",
    Age: 13
}

Ultimately the problem is that if I stick a breakpoint in my controller action I expect to see a populated Person object but it's always null. If I replace the signature to be something like (object name, object age) then I get values for the parameters (a string array for both - so name is a string array with 1 element which is equal to "James").

Any ideas where I've gone wrong?

Oh and just FYI, I'm not actually 13! Those were the first numbers I mashed.

Thanks!

James

Upvotes: 2

Views: 4068

Answers (2)

Kevin Junghans
Kevin Junghans

Reputation: 17540

@David is correct in that you need to set the contentType to 'application/json'. But you also need to send JSON. You are sending an object over. To convert it to JSON use JSON.stringify. I tried sending it over as an object with this contentType setting and received a server error. I actually got it to work correctly without setting the contentType. Even though the request came across as "Name=James&Age=13" MVC was able to convert it into an object. I modified your test to echo back the results as JSON and display them.

Here is the modified Controller

        [HttpPost]
    public string Add(PersonModel person)
    {
        JavaScriptSerializer serializer = new JavaScriptSerializer();
        string result = serializer.Serialize(person);

        return result;
    }

    // person model:
    public class PersonModel
    {

        public string Name { get; set; }
        public int Age { get; set; }

    }

The modified Javascript and HTML looks like this:

<input id="doAjax" type="button"  value="Send Json..."/>
<br />
Results:<br />
<textarea id="results" cols="30" rows="3"></textarea>
<script type="text/javascript">

 $( document ).ready( function () {
    $( "#doAjax" ).click( sendJson );
} );

function sendJson() {
    var name = "James";
    var age = "13";
    var person = { Name: name, Age: age };
    var personJson = JSON.stringify( person );
    $.ajax( {
        type: 'POST',
        url: "Test/Add",
        data: personJson,
        contentType: 'application/json',
        success: function ( data ) {
            var jsonStr = JSON.stringify( data );
            $( "#results" ).val( jsonStr );
        },
        error: function ( xhr, data, message ) {
            var jsonStr = JSON.stringify( data );
            $( "#results" ).val( jsonStr + ": " + message );
        },
        dataType: "json"
    } );
}

Here are the results of some tests:

data = person; contentType = not set; request = "Name=James&Age=13"; response = "{"Name":"James","Age":13}"

data = personJson; contentType = not set; request = "{"Name":"James","Age":"13"}"; response = "{"Name":null,"Age":0}"

data = person; contentType = 'application/json'; request = "Name=James&Age=13"; response = "System.ArgumentException: Invalid JSON primitive: Name"

data = personJson; contentType = 'application/json'; request = "{"Name":"James","Age":"13"}"; response = "{"Name":"James","Age":"13"}"

Note that when the contentType is not set it defaults to 'application/x-www-form-urlencoded'

Upvotes: 2

David Fox
David Fox

Reputation: 10753

The dataType passed to $.ajax is the expected response type. You need to add the contentType to specify the payload type.

$.ajax({
    type: 'POST',
    url: "Test/Add",
    data: { Name: name, Age: age },
    contentType: 'application/json' //*********
    success: function (data) {
        console.log("success");
    },
    error: function (xhr, data, message) {
        console.log(data + ": " + message);
    },
    dataType: "json"
});

Here's the jQuery documentation for .ajax() that indicates the default contentType is 'application/x-www-form-urlencoded'

Upvotes: 1

Related Questions