You’ve been there too. A month ago you wrapped up your first release. You were happy and went for a beer with your workmates. The next month things didn’t go so well. As you start integration testing again, you realize something has gone wrong. You dig down, and discover your app had serialized some useful data to disk not so long ago. Yet, as the new version does its thing, it crashes with a vengeance, when it tries to get that data back from the same place. As you sigh, and realize there won’t be any beer that night, you notice that those serialized bits of data have changed schema between deployments. You think - I do want the app to re-use that data without breaking… So how on Earth do I get around this?
The answer to this is remarkably simple - if your serialization code needs to tolerate versions… Then make it version tolerant!
Now there are many ways of making serialization version tolerant, and they all depend on how exactly you are serializing your data.
A direct approach can be to just JSON.NET-the-lot and go with that. And that’s fine, it works and pays the bills. Happy camping, Homer.
But what if you care about the milliseconds? What if you do want the brute speed and small size of binary serialization… and the benefits of text based version tolerance?
Well that’s a what version tolerant binary serializer is there for. (Again, the answer is so simple, it should be a criminal offense).
Below I’ll show you how to setup and use the Microsoft Bond serializer, so you get the best of both worlds.
My name is Bond… Microsoft Bond. Binary Martini… Shaken, not shifted.
Bond is Microsoft’s equivalent of Google’s Protocol Buffers and they both share the same traits:
- Some annoying platform independent script compilation (though Visual Studio makes it a lot better) - this is in exchange for…
- Fast binary (de)serialization by default. Bond uses a layered approach so you can mix and match features. The more you use, the more you pay, but it goes the other way too.
- Compact binary format.
- Platform and language agnostic - well kinda.
You can find the full sales pitch here.
Anyway, onwards to the how-to:
The first step is to go grab the Bond.CSharp NuGet package.
This package will bring the Bond dependency lot with it and make life easier for you. If for some reason you need to micromanage your dependencies, you can also go with the several other Bond.* packages.
Restart Visual Studio
The Bond Package will activate a new Custom Build option in Visual Studio. You need to restart the IDE for this to take effect.
Create a Bond File
Now create a dot bond file to hold your serializable types. And don’t shake your head now, stick with me here.
Bond shares the same necessary evil of Protocol Buffers. As it is a platform-independant serializer, you need to specify its types in a platform-independant way. Bond needs to know what types actually are, regardless of the platform in use. One platform may use Big Endian encoding while another uses Little Endian. One platform may encode strings with a length prefix while another platform uses an end marker. Who knows? Yet you still want both platform to speak to each other, even in high speed binary. Both Bond and Protobuf’s answer to this is to use their own uniform types and translate as needed for each different platform.
Set the file’s Build Action to BondCodegen</h2>
This will let Bond do some magic in the background and generate C# classes for you that mirror the types you wrote. You can also compile these bond files with the bond compiler, but I won’t dive into that here.
Write Some Code To Save
This will serialize an instance of that SomeBondClass to disk - but you can also send the bytes via the pipe, of course.
Note the lack of the using clauses. That surprised me at first, streams being all IDisposable and all. Not so much with Bond, it cleans after itself. If only my dog did that as well.
Check That File Up
This binary file stands at a measly 15 bytes. Serialize this tiny same class as JSON and you end up with 50 bytes. You are using only 30% of bytes as you would with JSON. Won’t even bother with XML at this point.
Write Some Code To Load
This will read the serialized data back into a class for you. Here’s the result:
Mess It Up
Okay, this is all nice but we haven’t made of use of any version tolerance whatsoever. So let’s make it so and break things up.
Introduce a change into your Bond class:
I just added a new property here for show, but do whatever you want.
Read It Back Again
Which is the behavior you’d get with say, JSON.NET - though for a much smaller file size, which is ideal for piping over or persisting to disk.
I’m growing fond of Bond over time as another useful tool for implementing real-time systems. Anything that helps grab that extra millisecond helps. I may even start drinking Martini again.
Till next time.