BSON (Binary JSON) and how your Web API can be even faster

I have been reading the wishlist at Web API Codeplex repository recently, and noticed that one of the most popular requested features, is to add support for BSON (Binary JSON) media type (6th on the list).

Of course all it takes to include BSON into your Web API is to simply write a media type formatter for it, and since JSON.NET already has great BSON support, it is actually quite easy.

Now, you might be asking a question, why to do it in the first place? Isn’t JSON enough? Well, the main reason is performance, as according to JSON.NET tests, BSON would produce output that’s often smaller than JSON (up to 25%). It is also much quicker to encode and decode, as for simple types there is no parsing to/from their string representation.

Let’s do it then.

About BSON

If you are still unsure about using BSON, you can find more information about the specification here, and of course at Wikipedia. The format has been popularized by MongoDB, and is a great alternative to binary/JSON/XML way of passing the data between the various systems.

The main advantage is that if you for example have a an integer, it doesn’t get converted to a string and back to integer when you are serializing/deserializing your POCO.

Creating the formatter

So what we need is a new media type formatter. If you are unfamiliar with the concept, take a look at my previous articles: about media type formatters and about content negotiation.

To create a media type formatter, we inherit from System.Net.Http.Formatting.MediaTypeFormatter.

We will have to override the methods shown below. Please note, this is relevant for Web API RC, because in RTM these signatures change slightly (i.e. HttpContent instead of HttpContentHeaders is passed).

In this example we will follow the conventions of the Web API source code, so in addition to the necessary overrides, we expose some public members of the formatter the same way the default Web API JSON.NET formatter does.

Let’s start with a constructor though.

We start off by telling the formatter to support “application/bson” media type. We also initialize our private JSON.NET serializer settings for later use.

The default serialization settings are the same as those of the default Web API JSON.NET formatter. Additionally, you can set your own if you wish, through the use of the public property.

Now let’s handle the CanReadType and CanWriteType methods.

Since JSON.NET can serialize any CLR types, we will always return true for both methods, as long as a type is passed to the formatter.

Finally, let’s deal with writing to the stream (serialization) and reading from the stream (deserialization).

The “write” code should be very straightforward. We use JSON.NET’s BsonWriter to serialize our object. We run the serialization synchronously (hence the use of TaskCompletionSource), the same way as Web API does it, because there is no real advantage of switching threads for these simple operations.

Now the deserialization:

While this method is also fairly simple, two notes here. We need to use IsAssignableFrom to determine if the deserialized type is a collection. This is a limitation of BSON as it cannot automatically detect the root container type. If it is, we treat the entire BSON as a collection.

The second thing worth noting is the error handling. This is actually copied from the ASP.NET Web API source, and that’s exactly how the default JSON.NET formatter handles the errors. The goal is, as mark all exceptions as handled, as otherwise it may be rethrown at each recursive level and overflow the CLR stack.

Plugging it in

As usually, we need to plug it into our GlobalConfiguration.

Consuming BSON serialized types

Now let’s see this in practice. I will be testing with a couple of simple Console app methods.

In this test example I am using a simple MyType class which has one property only, a string Name.

It looks like this in Fiddler (binary response):

This returns the following output (binary response can be deserialized smoothly):

Now, what I can do as well, obviously, is I can post an item back using the BSON format.

Now if I enumerate all of them again, I can see it has been added.

Finally, let’s see if the performance really improves with BSON. JSON.NET actually comes in with nUnit performance tests. If you run those you’d see that BSON gives the smallest size, and usually outperforms JSON and is right on par or faster than DCS.

Summary and source code

As you can see, you can easily add BSON support for your Web API, and benefit from its performance. Of course it is not suitable for sending down to the browser, but whereever your client has the capabilities of deserializing BSON (i.e. any .NET client which has access to JSON.NET), then you should definitely consider providing BSON media type from your API.

Source code, as always, included.

source code (gist)