Careful with Serialization

There are times when you need to share data over different processes, applications or computers. For this purpose, you can use various tools and mechanisms. The one thing they have in common is data serialization, and when you do it wrong, you are in big trouble.

Let’s take a look at a simple example of sharing data through the file. Firstly, we save the date value to a new one and pretend that this code is running on one computer.

var firstDate = new DateTime(2013, 10, 12);

using (var file = File.Create(fileName))
using (var writer = new StreamWriter(file))
{
    writer.WriteLine(firstDate.ToString());
}

Secondly, we deserialize the value on another computer and parse it into new variable. Nothing special so far, really.

using (var file = File.OpenRead(fileName))
using (var reader = new StreamReader(file))
{
    var firstDate = DateTime.Parse(reader.ReadLine());
}

It seems alright, doesn’t it? If you think so, you just introduced a bug to your application.

The problem is that the serialization and deserialization are dependant on the current locale of a machine. Imagine that the first process is running under en-US and the second one is en-GB; what would happen?

The first process is trying to share October 12 and the second one reads it as a December 10. Along with this, for the first twelve days of a month this mistake is silently hidden, your program runs with incorrect data and you might not even notice. For the rest of the month and different data types, like numbers, FormatException is raised.

Avoiding this mistake is pretty easy. You should always specify invariant format when doing a conversion, and do it on both sides. The easiest solution is to use CultureInfo.InvariantCulture, but any custom format will do the job.

And so, the corrected version of our previous example would look like this.

var firstDate = new DateTime(2013, 10, 12);
            
using (var file = File.Create(fileName))
using (var writer = new StreamWriter(file))
{
    writer.WriteLine(firstDate.ToString(CultureInfo.InvariantCulture));
}

And the second process should use invariant culture for parsing as well.

using (var file = File.OpenRead(fileName))
using (var reader = new StreamReader(file))
{
    var firstDate = DateTime.Parse(reader.ReadLine(), CultureInfo.InvariantCulture);
}

In conclusion, always remember to specify invariant format when using ToString() method to serialize and deserialize data. Never ever rely on default computer locales. They can be the same now, but they won’t be later and you don’t want to waste your time on such silly mistakes.