Monday, May 28, 2012

Asp.net Ajax : How to send complex objects from javascript


Asp.net Ajax : How to send complex objects from javascript

In this post I will show :
  • How to call Asp.Net Page Methods using jQuery
  • How to call page method with multiple arguments
  • How to send complex objects with jQuery
  • How to handle different types of objects within the same page method
  • How to Return Complex Objects from Page Method

How to call Asp.Net Page Methods using jQuery

First let's define a simple page method that will handle the requests.
[System.Web.Services.WebMethod]
public static string TestMethod(string data)
{
  return "Data received at " + DateTime.Now.ToString();
}
now we can use the $.ajax method of jQuery to make calls to the page method we defined. Lets look how can we send a simple string:
// send a simple string
var data2Send = '{"data":"this is a simple string"}';
$.ajax({
    type: "POST",
    url: 'Default.aspx/Testmethod',
    data: data2Send,
    contentType: "application/json; charset=utf-8",
    dataType: "json",
    success: function (arg) { //call successfull
    },
    error: function (xhr) {
        //error occurred
    }
});

There are two important rule here : First we define a simple page method to make requests to. now we can use the $.ajax method of jQuery to make calls to the page method we defined. Lets look how can we send a simple string:

we see that firebug already show the parameter as a json value. If the data is not a valid json object Asp.Net will throw an exception
{"Message":"Invalid JSON primitive:","StackTrace":..."
Second the parameter name of the Asp.Net Page Method must be same with the property name of json object we send to the server.

If parameter names are different Asp.Net will throw another exception. For example if we send
{"test":"this is a simple string"}
json object to TestMethod we will receive the exception below :
{"Message":"Invalid web service call, missing value for parameter:data"}
which states the page method was waiting for a json argument with a property named data but could not find one. On the other hand if we send a json object containing multiple property, Asp.Net will check the parameter to see if it contains a property with the same name as its parameter name. In our example it will search the object for a property name data. So if we send
{"test":"this is a simple string","data":"test"}
our page method will pick the 'data' property and will not take other properties of the json object into consideration.

How to call page method with multiple arguments

if we want to call a page method with multiple arguments all we need to construct a json object with the same property names as the parameter names of the page method. Say we have an Asp.Net page method like this :
[System.Web.Services.WebMethod]
public static string TestMethod(string data, string arg)
{
   return "Data received at " + DateTime.Now.ToString();
}

Now in order to call this page method from javascript first we need to define a json object with properties named "data" and "arg" then make a request with "jQuery.ajax method".
// send an object with multiple parameters
var data2Send = '{"data":"this is a simple string", "arg":"hello"}';
 
$.ajax({
    type: "POST",
    url: 'Default.aspx/Testmethod',
    data: data2Send,
    contentType: "application/json; charset=utf-8",
    dataType: "json",
    success: function (arg) { //call successfull
    },
    error: function (xhr) {
        //error occurred
    }
});

Here is the result :

How to send complex objects with jQuery

After some basic information about how can we send simple types to page methods with jQuery now its time to see how we can send complex objects. First lets define a relatively complex javascript object.
var data = {
    name: 'Cem',
    surname: 'Karaca',
    birthDate: '05.04.1945',
    groups: [{
        name: 'Kardaslar',
        Year: 1970,
        members: ['Unol Buyukgonenc', 'Seyhan Karabay', 'Huseyin Sultanoglu', 'Fehiman Ugurdemir']
    },
    {
        name: 'Dervisan',
        Year: 1974,
        members: ['Ugur Dikmen', 'Sefa Ulastir', 'Hami Barutcu']
    }],
    links: ['http://en.wikipedia.org/wiki/Cem_Karaca', 'http://progressive.homestead.com/Cem_Karaca.html']
};

Now first we need to convert this javascript object to an json object. Although we can do that without using an additional library its better to use one as it turns out that converting manually can be error prone.
If you use Asp.Net ajax library there are already two methods that deal with javascript serialization. You can serialize and deserialize javascript objects with Asp.Net Ajax library with the following code :
var data = {
    name: 'cem',
    surname: 'karaca'
}
//serialize object to json
var jsonData = Sys.Serialization.JavaScriptSerializer.serialize(data);
 
//deserialize json to javascript object
var obj = Sys.Serialization.JavaScriptSerializer.deserialize(jsonData);

The other option is to use Dougles Crockford's json library. Here how we can serialize and deserialize objects with this library
var data = {
    name: 'cem',
    surname: 'karaca'
}
//serialize object to json
var jsonData = JSON.stringify(data);
 
//deserialize json to javascript object
var obj = JSON.parse(jsonData);

I will use second library for the example. First lets define another page method to handle the complex type that we will send using jQuery.
[System.Web.Services.WebMethod]
public static string ComplexTypes(object data)
{
  return "Data received at " + DateTime.Now.ToString();
}

and here is the javascript part of the code
// construct a complex object
var complexObj = {
    name: 'Cem',
    surname: 'Karaca',
    birthDate: '05.04.1945',
    groups: [{
        name: 'Kardaslar',
        Year: 1970,
        members: ['Unol Buyukgonenc', 'Seyhan Karabay', 'Huseyin Sultanoglu', 'Fehiman Ugurdemir']
    },
    {
        name: 'Dervisan',
        Year: 1974,
        members: ['Ugur Dikmen', 'Sefa Ulastir', 'Hami Barutcu']
    }],
    links: ['http://en.wikipedia.org/wiki/Cem_Karaca', 'http://progressive.homestead.com/Cem_Karaca.html']
};

//our page method has a single parameter named 'data'
//so we have to construct a json object with a 'data' property 
//and complexObj will be the value part
//so our json object must be in form {"data":complexObj}
//construct a new javascript object with a property named data
//which contains the complexObj as value
 
var obj = { data: complexObj };
 
var data2Send = JSON.stringify(obj);//convert obj to json
 
//call the ComplexTypes page method with
$.ajax({
    type: "POST",
    url: 'Default.aspx/ComplexTypes',
    data: data2Send,
    contentType: "application/json; charset=utf-8",
    dataType: "json",
    success: function (arg) { //call successfull
    },
    error: function (xhr) {
        //error occurred
    }
});

Here is the request data that we send from client to server
and here is the data parameter that we receive in page method.

Asp.net processed the posted data and all of its properties as a dictionary object. Now although it is easy to work with dictionaries in .Net it is not very useful for complex objects like the one we posted.Fortunately Asp.Net provides another way to parse the received data.
What we need to create a new class with the same structure as the passed data and change the paremeter type of the page method from object to the new class we create. Again the structure of the javascript object we send to the server :
var data = {
    name: 'Cem',
    surname: 'Karaca',
    birthDate: '05.04.1945',
    groups: [{
        name: 'Kardaslar',
        Year: 1970,
        members: ['Unol Buyukgonenc', 'Seyhan Karabay', 'Huseyin Sultanoglu', 'Fehiman Ugurdemir']
    },
    {
        name: 'Dervisan',
        Year: 1974,
        members: ['Ugur Dikmen', 'Sefa Ulastir', 'Hami Barutcu']
    }],
    links: ['http://en.wikipedia.org/wiki/Cem_Karaca', 'http://progressive.homestead.com/Cem_Karaca.html']
};

and here is the new class we constructed to handle the posted data.
public class MyData
       {
           public class Group
           {
               public string Name { get; set; }
               public int Year { get; set; }
               public List<string> Members { get; set; }
           }
           public string Name { get; set; }
           public string SurName { get; set; }
           public string BirthDate { get; set; }
           public List<Group> Groups { get; set; }
           public string[] Links { get; set; }
       }

and finally here is the new signature of the page method with the parameter type of 'MyData '.
[System.Web.Services.WebMethod]
public static string ComplexTypes(MyData data)
{
   return "Data received at " + DateTime.Now.ToString();
}
and here is the result :

We have successfully parsed the posted data as a strongly typed object.

How to handle different types of objects within the same page method

There can be times when we want to or have to use the same page methods for all objects posted from javascript. In order to achieve this we need to send objects as string data to our page method. Then we will use the free Json.Net to convert our json formatted string data to .net objects. First lets look at the javascript code :
//Send Complex Type1 as string to Json.Net
//define and object that will be sent to server
var simpleObj = {
    name: 'Cem',
    groups: ['Apaslar', 'Kardaslar']
};
 
//define a javascript object which has a  property named data
//the value of data property must be string 
//so we need to convert our obj
data2Send = JSON.stringify({
    data: JSON.stringify(simpleObj),
    type: 'type1'
});
 
$.ajax({
    type: "POST",
    url: 'Default.aspx/MultipleTypes',
    data: data2Send,
    contentType: "application/json; charset=utf-8",
    dataType: "json",
    success: function (arg) {
        //print the server response
        $result.html(arg.d);
    }
});

The important thing is to convert the object to string type and also using another type to differentiate the object in the server. Now lets look at the server side code.
[System.Web.Services.WebMethod]
public static string MultipleTypes(string data, string type)
{
    switch (type)
    {
        case "type1":
            {
                var type1 = new
                {
                    name = String.Empty,
                    groups = new List<string> {}
                };
                var result = Newtonsoft.Json.JsonConvert.
                    DeserializeAnonymousType(data, type1);
 
            }
            break;
        case "type2":
            {
                var type2 = new { text = String.Empty };
                var result = Newtonsoft.Json.JsonConvert.
                    DeserializeAnonymousType(data, type2);
            }
            break;
    }
 
    return "Data received at " + DateTime.Now.ToString();
}

Our page method has two parameter data and type. The data parameter will contain the json formatted javascript object and the type parameter will contain the type information that will be used to differentiate the structure of the posted data. The JsonConvert.DeserializeAnonymousType method of Json.Net library takes a json formatted string and a anonymous type that has the same structure of the json data and return a .net object. Here is the result :




As seen from the result we handled different types of objects that are sent from javascript within the same page method easily using Json.Net library.

How to Return Complex Objects from Page Method

It's very easy to return complex object from Asp.Net page method. All we need to do is to define a page method that has return type of object and construct an anonymous type.Here is the C# code :
[System.Web.Services.WebMethod]
public static object ReturnComplexType()
{
    return new
    {
        data = "Hello from server",
        time = DateTime.Now.ToString(),
        array = new string[]{"", "Yart", "Cem"}
    };
}

Also note that in order to call this page method we have to construct an empty javascript object as the value for the data property of the $.ajax method. Here is the javascript code to call "ReturnComplexType" page method.
$.ajax({
    type: "POST",
    url: 'Default.aspx/ReturnComplexType',
    data: {},
    contentType: "application/json; charset=utf-8",
    dataType: "json",
    beforeSend: function () {
        $result.html("Sending Data...");
    },
    success: function (arg) {
        $result.html(arg.d);
    }
});

and here is the received object from javascript.


As you can see it is very easy to send and receive complex objects using Asp.Net with jQuery. Also because the json format is used as the data interchange format the page is very responsive and server footprint is very low. Hope it helps.

1 comment: