One of the new features introduced in 2.1.0 of the Couchbase .NET SDK was support for overriding the default serializer with your own custom serializer by extending the ITypeSerializer interface and providing your own or favorite serializer. In this article we will show you how to do this and provide an example (clonable from couchbase-net-contrib project in Couchbaselabs) using a very fast JSON serializer called Jil.

By default the .NET SDK uses the popular NewtonSoft.NET JSON serializer mainly because it’s a feature complete, widely used and well-supported project. In general the performance provided by the NewtonSoft is good enough for most projects, in some cases however, you may want to use a faster JSON serializer like Jil.

Jil is based off of Sigil, a fail-fast IL generation library, and provides a general purpose JSON serializer which is highly optimized and uses a number of “tricks” to improve performance, like avoiding allocations (thus no GC’s) and optimizing the member access order so the CPU doesn’t need to stall while waiting for values in memory. You can read more about Jil and Sigil here and here.

Steps Required

Extending the default serializer is relatively easy:

  1. First you provide your own implementation of Couchbase.Core.Serializaton.ITypeSerializer.
  2. Then override the DefaultSerializer in Couchbase.Configuration.Client.ClientConfiguration class. That’s it!
  3. Optionally, you may wish to use the Web.Config or App.Config to register the new ITypeSerializer so that the SerializerFactory will create the serializer at run-time.

Implementing ITypeSerializer

The ITypeSerializer interface is used by the transcoder (ITypeTranscoder) for handling the serialization and deserialization of Memcached packet body. The transcoder uses the Type of the generic parameters of the operation, the OperationCode of the operation and the “flags” encoded within the Memcached header to determine what Type to de-serialize the body into and to determine which flags to encode the packet during serialization.

While is seems complex, it’s all really simple; if the Type of the body is an object or primitive (int, ulong,etc), the body is encoded with a JSON flag and treated as JSON. Yes, integers are treated as valid JSON! If the Type of the body is a string, it’s treated as a string and UTF 8 encoded or decoded. Finally, byte arrays are passed straight through and simply appended to the packet or read from the packet and assigned to the Value field of the IOperationResult, if the operation has a body. So any value other than Strings and byte arrays will be serialized or deserialized using the ITypeSerializer.

The ITypeSerializer has the following method signatures that you must implement:

One overload for Deserialize takes a Stream and the other a byte array, offset and length. Serialize just takes a System.Object reference which is the value to serialize into a byte array for transport.

The code listing for the JilSerializer looks like this:

Note that the code is near identical to the DefaultSerializer logic with exception that we are using the Jil JSON class instead of the Newtonsoft.NET serialization classes; although the serialization mechanism is different the rules are the same.

Configuring the SDK to use the custom Serializer

As mentioned earlier, the Couchbase .NET SDK was updated in 2.1.0 to allow for custom serializers, this is done by overriding the default serializer factory in the ClientConfiguration, which is just a Func property: anything matching the signature will be created and used for serialization. On a side note, the SerializationSettings and DeserializationSettings have been deprecated and are no longer used.

Here is an example:

While you can provide complex logic for the creation of the ITypeSerializer, the simplest approach is sufficient.

If you wanted to use the SerializationFactory to instantiate the serializer, you would simply provide the initialization code in your Web.Config or App.Config:

To use the custom configuration in your code, you will call the CTOR of the Cluster class which takes a string path that matches your configuration:

Once you do this, any Buckets opened from the Cluster object will use the JilSerializer instead of the default NewtonSoft.NET serializer.

Conclusion

With the new extension points added to the Couchbase .NET SDK, it’s trivial to write and use custom JSON serializers using the ITypeSerializer interface. The Jil JSON serializer looks impressive and is easy to use; I am hoping a community member will create one for ServiceStack.Text and push it to the Couchbase. NET Contrib Project!

Posted by Jeff Morris, Software Engineer, Couchbase

Leave a reply