Using jQuery Ajax methods in ASP.NET MVC: $.get() and $.getJSON() vs. $.post()
I’m currently working on a project that uses ASP.NET MVC and jQuery to do some Ajax magic, and I ran into a minor (but maybe not obvious) issue when using $.post() against an MVC action that returns a JsonResult.
The core issue is that calling $.get or $.post does not by default treat the returned data as Json, which $.getJSON does. [Also, there is no $.postJSON]
First, let’s setup a little test case using a simple get request.
Calling An Action From jQuery – $.getJSON
1: function DoAjaxCall() {
2: var url = '<%= Url.Action("AjaxTest", "Lookup") %>';
3:
4: $.getJSON(url,
5: null,
6: function(data) {
7: alert(data.name);
8: }
9: );
10: }
Our JavaScript here simple calls $.getJSON(), passing along the action url and expecting back some data with a name property. The action is implemented as follows:
1: public ActionResult AjaxTest()
2: {
3: var data = new { name = "TestName"};
4:
5: return Json(data);
6: }
Calling the Action using $.post
Let’s make a few changes so that we are posting data to the action and expecting back Json. The JavaScript changes slightly, with $.getJSON turning into $.post.
1: function DoAjaxCall() {
2: var url = '<%= Url.Action("AjaxTest", "Lookup") %>';
3:
4: $.post(url,
5: null,
6: function(data) {
7: alert(data.name);
8: }
9: );
10: }
All we need to do to the action method is to add an attribute so that it will restrict itself to accepting post requests.
1: [AcceptPost]
2: public ActionResult AjaxTest()
3: {
4: var data = new { name = "TestName"};
5:
6: return Json(data);
7: }
Note that [AcceptPost] is the same thing as [AcceptVerbs(HttpVerbs.Post)]. It can be found in MVC Contrib.
When we run this example, we get a post to the correct method, but our alert box shows only ‘undefined’.
A trip into FireBug shows that our response was the following: {"name":"TestName"}
Everything looks good there, but the problem is obviously that $.post is not interpreting the return value as JSON. If you debug into the $.post callback you see that the value of the data parameter is this: "{\"name\":\"TestName\"}".
So it appears the result was stringified. The fix is to specify the type of data to be returned to the callback function as the fourth parameter to $.post(). Possible values are: "xml", "html", "script", "json", "jsonp", or "text".
Let’s try specifying the type parameter and setting it to ‘json’:
1: function DoAjaxCall() {
2: var url = '<%= Url.Action("AjaxTest", "Lookup") %>';
3:
4: $.post(url,
5: null,
6: function(data) {
7: alert(data.name);
8: },
9: 'json'
10: );
11: }
Success! If we look at the POST response it is the same as before, but now we get the proper alert message to display “TestName”. If we debug through with firebug we see data is now an object with a single property of name (that has the value “TestName”).
What I learned
jQuery’s $.get and $.post do not natively parse the result as JSON. $.get has a helper called $.getJSON which will do the job for you, though you can achieve the same result by using $.get and passing the string ‘json’ as the fourth “type” parameter. Since there is no $.postJSON, if you are doing a jQuery ajax post and expecting a JsonResult, you must always pass ‘json’ as the fourth parameter to $.post.