Custom Serialization

Azure Cache (Preview) release added support for using a custom serializer to serialize objects that are stored in the cache.

NetDataContractSerializer is the default serialization mechanism used by Azure cache. Many times, applications might need to use custom serialization for performance or compatibility reasons.

 An application could explicitly serialize objects and store them in cache as byte[]'s. However, this  results in sub-optimal performance when local cache is used since the cost of deserialization will be incurred even when retrieving items from local cache. Using the custom serializer support, access to objects in local cache does not incur any deserialization costs (on-par with default serialization approach).

 

Let's walk through a code example

 

Instead of the default NetDataContractSerializer, we will create a custom serializer that uses Json serialization to serialize instances of Person class.  Since we will use DataContractJsonSerializer for this example, we need to attribute this class as a DataContract.

 

     [DataContract]

    publicclassPerson

    {

        public Person(string firstName, string lastName)

        {

            this.FirstName = firstName;

            this.LastName = lastName;

        }

 

        [DataMember]

        publicstring FirstName { get; set; }

 

        [DataMember]

        publicstring LastName { get; set; }

 

    }

 

Implement the IDataCacheObjectSerializer interface

 

Custom serializers need to implement the IDataCacheObjectSerializer interface - It has 2 methods (one each for Serialize and Deserialize).  For this example, we will keep the implementation simple and use the System.Runtime.Serialization.Json.DataContractJsonSerializer class to do the actual work.

 namespace WorkerRole1

{

    /*

     * Simple implementation of IDataCacheObjectSerializer

     * Uses DataContractJsonSerializer

     */

    publicclassCustomSerializer: IDataCacheObjectSerializer

    {

        public CustomSerializer()

        { }

        publicobject Deserialize(System.IO.Stream stream)

        {

            Trace.WriteLine("CustomSerializer.Deserialize method called");

           

            DataContractJsonSerializer serializer = newDataContractJsonSerializer(typeof(Person));

 

            return serializer.ReadObject(stream);

 

        }

 

        publicvoid Serialize(System.IO.Stream stream, object value)

        {

 

            Trace.WriteLine("CustomSerializer.Serialize method called");

                       

            DataContractJsonSerializer serializer = newDataContractJsonSerializer(typeof(Person));

 

            serializer.WriteObject(stream, value);

 

 

        }

    }

 

Configure Cache Client to use the Custom Serializer

 

This can be done either through xml configuration or through code.

 

Through XML Configuration: 

Add the <serializationProperties /> element specifying serializer="CustomSerializer" and setting customSerializerType to the type that implements the custom serialization. In this case, WorkerRole1.CustomSerializer is the name of the class located in WorkerRole1.dll

 

  <dataCacheClients>

    <tracing sinkType="DiagnosticSink" traceLevel="Verbose" />

    <!-- This is the default config which is used for all Named Caches

     This can be overriden by specifying other dataCacheClient sections with name being the NamedCache name -->

    <dataCacheClient name="default" useLegacyProtocol="false">

      <autoDiscover isEnabled="true" identifier="WorkerRole1" />

      <!--<localCache isEnabled="true" sync="TimeoutBased" objectCount="100000" ttlValue="300" />-->

      <serializationProperties serializer="CustomSerializer" customSerializerType="WorkerRole1.CustomSerializer,WorkerRole1" />

    </dataCacheClient>

  </dataCacheClients>

 

You can also configure the custom serialization properties through code as shown below:

 

            DataCacheSerializationProperties customSerializerProps = newDataCacheSerializationProperties(

                                        DataCacheObjectSerializerType.CustomSerializer,

                                        newCustomSerializer());

 

            DataCacheFactoryConfiguration config = newDataCacheFactoryConfiguration("default");

 

            // Specify CustomSerialization Properties.

            config.SerializationProperties = customSerializerProps;

 

            DataCacheFactory factory = newDataCacheFactory(config);

 

            DataCache cache = factory.GetDefaultCache();

 

Testing the custom serializer

 

 When you try out the code below that adds instances of type Person to cache, you can verify that the CustomSerializer class methods are being called.

Person p = new Person("Jagan", "Peri");
cache.Put("key1", p);
Person p2 = (Person)cache.Get("key1");

Limitations

 

1) As you can see from the above code snippets, there can be only one custom serializer specified at a DataCacheFactory level. If your application stores multiple types in the cache, the custom serializer needs to handle all these types.

2) Some APIs (increment, decrement, Append, Prepend) are not supported with custom serialization. These APIs require the cache server to understand the value stored in the cache
so it can perform these operations atomically on the value. Since custom serializer  is only available on the client, these APIs cannot be used with custom serialization.

 

Sample Project

 

 I've attached a sample worker role that uses co-located cache and demonstrates the use of the above interface.

Key files to look at in this project are:

Person.cs - Type that is stored in cache

CustomSerializer.cs - Custom Serializer implementation

WorkerRole.cs - Configures CustomSerialization and performs cache put/get API calls.

 

 

 

 

 

CustomSerializer.zip

Comments

  • Anonymous
    August 29, 2012
    Thanks for the great article! Is there any possibility to use custom cache serializer with Windows Server AppFabric? Thanks is advance.

  • Anonymous
    September 08, 2012
    @Alex - Only Azure cache (preview) has this support at the moment.

  • Anonymous
    October 02, 2012
    Thanks for your article! Is it possible to write a custom serializer for generic type? In your artile, that serializer is only working for Person. Thanks again.