Monday 21 November 2011

Ajax with jQuery and JSON in ASP.NET MVC 3

In this article, we'll see how to do Ajax request using HTTP POST method in ASP.NET MVC 3. The recent MVC framework allows this to be done easily.

First we prepare our html controls.
<input id="ajaxBtnPostOne" value="Ajax Button Post 1" param="1" type="button" />
<div id='ajaxDiv'></div>

Then the javascript codes. Make sure you have jQuery library in the application. In this article, I use jQuery 1.5.1.
$(document).ready(function () {
    $("#ajaxBtnPostOne").click(function (event) {
        $.ajax({
            type: "POST",
            url: "/Teams/GetDetailsUsingHttpPost", 
            data: "{ 'id':'" + $('#ajaxBtnPostOne').attr('param') + "'}",
            contentType: "application/json; charset=utf-8",
            dataType: "json",
            success: AjaxSucceeded,
            error: AjaxFailed
        });
    });
});

function AjaxSucceeded(data) {
    alert('success');
    //write content to a div
    $('#ajaxDiv').html(data);
}

function AjaxFailed(result) {
    alert('an error has occured: ' + result.status + ' ' + result.statusText);
    alert(result.responseText);
}
Note that we use jQuery function $.ajax() to bind to the 'on clicked' event of the html button we have above.
The settings on this method:
- type: we want use HTTP POST.
- url: this is the url where the Ajax call will be posted to. In this case is the location of the server side method 'GetDetailsUsingHttpPost' that we are going to create below.
- data: this is the data that will be passed to the method.
- dataType: we want to use JSON in this case.
- success: what to do when the Ajax call is returned successfully, in this case we execute a method.
- error: what to do if an error occurred, in this case we execute a method.

Then we have the server side receiver method. In MVC, we can simply use a controller method to handle an Ajax call. No extra configuration is needed.
[AcceptVerbsAttribute(HttpVerbs.Post)]
public JsonResult GetDetailsUsingHttpPost(int id)
{
    Team team = teamRepository.Find(id);
    return Json("Team Name = " + team.Name);
}
Note that '[AcceptVerbsAttribute(HttpVerbs.Post)]' attribute is used so that the method will only respond to a POST method. When Ajax call is used with JSON to query sensitive information, it is recommended to use POST method. Please see http://haacked.com/archive/2009/06/25/json-hijacking.aspx for more details.

Also notice that the method accept an integer parameter however the passed data is a string; the framework does the conversion automatically. Note that the variable name ('id') used in the 'data' setting of the javascript function is the same as the one accepted by the method.

To return JSON data, we just need to put the data to be returned inside Json() method and specify the controller method's return type as JsonResult.

Say now we want to return an object instead of a string. To do this, we can simply use an anonymous type or a class. If we choose to use a class then prepare our class, eg. TeamViewModel:
public class TeamViewModel
{
    public int TeamId { get; set; }
    public string Name { get; set; }
}
No extra configuration is needed to return an anonymous type or a class' object to the Ajax call. Here is our modified controller method:
/*modified to return an object instead of string data*/
[AcceptVerbsAttribute(HttpVerbs.Post)]
public JsonResult GetDetailsUsingHttpPost(int id)
{
    Team team = teamRepository.Find(id);
    TeamViewModel teamVM = new TeamViewModel();
    teamVM.TeamId = team.TeamId;
    teamVM.Name = team.Name;
    return Json(teamVM);

    // we could also have used an anonymous type instead
    //var anonymousTeam = new { TeamId = team.TeamId, Name = team.Name, City = "sydney" };
    //return Json(anonymousTeam);
}
We need to change the js function that is called when the Ajax call is successful:
function AjaxSucceeded(objdata) {
    alert('success');
    alert(objdata.TeamId + ' - ' + objdata.Name);
    $('#ajaxDiv').html(objdata.TeamId + ' - ' + objdata.Name);
}
Notice that the received object has similar structure as the returned object's type from the controller method; ie. it has 'TeamId' and 'Name' members. It also preserve the case sensitivity of the properties; if we use small case letters 'objdata.teamid' instead of 'objdata.TeamId', this will be rendered as 'undefined'.

On the next post, we will see how to pass object(s) in the Ajax function.

No comments: