In this article we’ll examine the ASP.NET AJAX serialization process. We will examine the server-side methods and client-side methods which serialize and deserialize objects.

What is JavaScript Object Notation (JSON)?

JavaScript Object Notation or JSON provides a more efficient means of transferring data than previously found with XML and SOAP. JSON is a means of basically serializing an object into a lightweight string that can be sent across the wire. For example, consider the following C# class:

public class User
{
    string FirstName;
    string LastName;
}

Now consider an instance of the object as follows:

User usr = new User();
usr.FirstName = "John"
usr.LastName = "Smith";

When serialized into JSON formatted text we’ll be left with the following:

{ FirstName : "John"
LastName : "Smith" }

From within JavaScript we can deserialize the JSON text string into an object using the JavaScript supplied method eval() or the class Sys.Serialization.JavaScriptSerializer. Using the AJAX class we can also serialize a JavaScript object to be sent to the server, we can then use the server-side object JavaScriptSerializer to deserialize the JSON text string object as we will discover in this article.

Getting Dirty

The object responsible for serialization/deserialization is the JavaScriptSerializer object. The relevant members of this object can be seen below.

public class JavaScriptSerializer
{
    // Fields
    internal const int DefaultMaxJsonLength = 0x200000;
    internal const int DefaultRecursionLimit = 100;
    internal const string ServerTypeFieldName = "__type";

    // Methods
    static JavaScriptSerializer();
    public JavaScriptSerializer();
    public JavaScriptSerializer(JavaScriptTypeResolver resolver);
    public T ConvertToType(object obj);
    public T Deserialize(string input);
    public object DeserializeObject(string input);
    public void RegisterConverters(IEnumerable converters);
    public string Serialize(object obj);
    public void Serialize(object obj, StringBuilder output);

    // Properties
    public int MaxJsonLength { get; set; }
    public int RecursionLimit { get; set; }
    internal JavaScriptTypeResolver TypeResolver { get; }
}

First off, the serialization process will fail if the number nested objects are greater than that defined within the RecursionLimit property. That said; note the default recursion limit of 100. The serialization process will also fail if the length of the serialized text is greater than that of the MaxJsonLength property; again note the default value of 2,097,152 base ten.

The object is serialized into a StringBuilder object, which after serialization has been completed, the string representation will be returned. The majority of the action happens within the private SerializeValue() method. Before we examine this method, it’s worth noting that the JavaScriptSerializer object may make use of the JavaScriptTypeResolver object. Which is used to resolve a type from a string and vice versa, which is important when custom objects are serialized. The __type attribute will be included within the JSON serialized text, hence indicating the object type. The client will then deserialize the JSON text into an object and populate the indicated properties with the values found within the JSON serialized text.

The JavaScriptTypeResolver object includes two public methods, one to resolve the type to string, and the other string to type. The class prototype is as follows:

public abstract class JavaScriptTypeResolver
{
    // Methods
    protected JavaScriptTypeResolver();
    public abstract Type ResolveType(string id);
    public abstract string ResolveTypeId(Type type);
}

The JavaScriptTypeResolver class is a base abstract class and should be implemented by another object which can be used to resolve the type to string and vice versa. The object which we may use is the SimpleTypeResolver and implements the above methods exactly as expected – making use of the System.Type object to resolve either a string representation into a valid Type object or a valid Type object into a string representation. See below. The JavaScriptTypeResolver class is a base abstract class and should be implemented by another object which can be used to resolve the type to string and vice versa. The object which we may use is the SimpleTypeResolver and implements the above methods exactly as expected – making use of the System.Type object to resolve either a string representation into a valid Type object or a valid Type object into a string representation. See below.

public override Type ResolveType(string id)
{
    return Type.GetType(id);
}

public override string ResolveTypeId(Type type)
{
    if (type == null)
    {
        throw new ArgumentNullException("type");
    }
    return type.AssemblyQualifiedName;
}

Finally, the JavaScriptSerializer object may also make use of a JavaScriptConverter object as the internal serialization process is not capable of serializing all available data types, in which case an object can inherit from the base abstract JavaScriptConverter object and implement the serialization/deseralization process for specific data types. A converter object may be registered with the JavaScriptSerializer using the RegisterConverters() method which stores all converter objects in a Dictionary object as multiple converters may be registered for multiple different data types. The Dictionary object is defined as follows:

Table 1 – Serialization of data types
Data type Serialized as
null or DBNull "null"
string Quoted string
char If ‘\0’, "null". Else serialized as a quoted string.
bool "true" or "false"
DateTime "\/Date(ticks since 12:00AM 1970/01/01 UTC)\/"
Guid “string representation”: sb.Append("\"").Append(guid.ToString()).Append("\"");
Uri sb.Append("\"").Append(uri.GetComponents(UriComponents.SerializationInfoString,UriFormat.UriEscaped)).Append("\"");
double sb.Append(((double) o).ToString("r", CultureInfo.InvariantCulture));
float sb.Append(((float) o).ToString("r", CultureInfo.InvariantCulture));
primitive or decimal

IConvertible convertible = o as IConvertible;
sb.Append(convertible.ToString(CultureInfo.InvariantCulture));

Enum sb.Append((int) o);
IDictionary

JSON text, for example.
{"Key1":Value1,"Key2":Value2 ... }

IEnumerable

JSON text, for example.
{"Key1":Value1,"Key2":Value2 ... }

A custom object is serialized similar to an IDictionary, with a few differences. If a JavaScriptTypeResolver object has been defined, the object type will be converted to a string and the object definition will include the string literal __type followed by the string representation of the object data type. The remaining objects properties and fields are obtained by looping the fields and properties obtained from the Type object. All fields and properties which have been defined as public and do not include the metadata ScriptIgnoreAttribute property will be included within the JSON object representation of the object.

Let us now examine the serialization process by way of an example object. Considering the objects defined below.

public class Customer
{
    private string _firstName;
    public string FirstName
    {
        get { return _firstName; }
        set { _firstName = value; }
    }

    private string _lastName;
    public string LastName
    {
        get { return _lastName; }
        set { _lastName = value; }
    }

    private string _email;
    public string EmailAddress
    {
        get { return _email; }
        set { _email = value; }
    }

    private Phone _phoneNumber;
    public Phone PhoneNumbers
    {
        get { return _phoneNumber; }
        set { _phoneNumber = value; }
    }

}

public class Phone
{
    private string _homePhone;
    public string HomePhone
    {
        get { return _homePhone; }
        set { _homePhone = value; }
    }

    private string _workPhone;
    public string WorkPhone
    {
        get { return _workPhone; }
        set { _workPhone = value; }
    }
}

If this object were returned from a web service method, the object would be serialized automatically from within the InvokeMethod() of the RestHandler, however in the sample case above, we’re making use of these objects from within our Page.Page_Load() method, hence we should create the objects and serialize them automatically using the JavaScriptSerializer object previously examined. Consider the following code to serialize an object.

JavaScriptSerializer jsSerializer = new 
JavaScriptSerializer(new SimpleTypeResolver());
Customer cust = new Customer();
cust.FirstName = "Joe";
cust.EmailAddress = "jknown@domain.com";
cust.PhoneNumbers = new Phone();
cust.PhoneNumbers.HomePhone = "888-888-8888";

string serializedText = jsSerializer.Serialize(cust);

Notice that the JavaScriptSerializer object has been initialized with the SimpleTypeResolver which as you know, will be invoked to evaluate the type of the serialized object to a string. The serialized JSON text is shown below.

{"__type":"Customer, App_Web_plrzlwbj,
Version=0.0.0.0, Culture=neutral,
PublicKeyToken=null","FirstName":"Joe","LastName":null,
"EmailAddress":jknown@domain.com,
"PhoneNumbers":{"__type":"Phone, App_Web_plrzlwbj, Version=0.0.0.0, 
Culture=neutral, PublicKeyToken=null",
"HomePhone":"888-888-8888","WorkPhone":null}} 

Notice that the PhoneNumbers property is of the custom type Phone, hence when serialized the value of the PhoneNumbers property will be a JSON object, which is the serialized version of the Phone object, again notice the type is identified, which is used when deserialized so that the correct object may be created and populated. That said, let us now examine the deserialization process.

The deserialization process is performed using the JavaScriptObjectDeserializer object, which when an instance is created, the JSON text string should be supplied as a parameter to the constructor. After an instance has been created, we may invoke the DeserializeInternal() method, here the JSON serialized string will be parsed and appropriate objects matching the serialized version will be created and populated.

To deserialize a JSON string we may invoke the Deserialize() method of the JavaScriptSerializer object. The return value being an instance of the initial object with the properties defined to the previously specified values. Consider the code below.

Customer cust = jsSerializer.Deserialize(serializedText);

Conclusion

That’s all there really is to it. We should now have a basic understanding of how the AJAX JSON serialization/deserialization process works and how we can leverage JSON serialization for use within our AJAX code. The process is really quite simple and light weight, not to mention that JSON text is much easier to parse client-side as opposed to XML serialization.