How to deserialize the data which is already serialized using BinaryFormatter in C#?

325 Views Asked by At

I have a ConcurrentDictionary which I serialized using the BinaryFormatter using the below code.

ConcurrentDictionary<string, DateTime> _jobsAck;
var binaryFormatter = new BinaryFormatter();
using (var stream = File.Open(BINARY_FILENAME, FileMode.OpenOrCreate))
{
    binaryFormatter.Serialize(stream, _jobsAck);
}

There are some security issues with the BinaryFormatter (Microsoft: Deserialization risks in use of BinaryFormatter and related types), so now I want to completely get rid of it. I now want to deserialize the content of the file using some other serializer.

I have tried many (XML serializer, NewtonSoft, ProtoBuf) but none is working (all throwing some exceptions). Could someone please help on this?

Target .NET Framework: 4.7.2

I can also go for .NET Standard <= 2.0 as well.

Edit: Approach to handle this case. So it keeps on serializing the content when a job is created. and on application start it loaded the data from file to the dictionary.

enter image description here

2

There are 2 best solutions below

0
György Kőszeg On BEST ANSWER

As I tried to highlight in the comments of my yesterday's answer, you will never be able to find a secure 3rd party implementation that can deserialize a BinaryFormatter stream because it would just mean the reintroduction of the vulnerabilities of BinaryFormatter. Apart from the most primitive types, BinaryFormatter saves everything with assembly qualified names that can be manipulated in the serialization stream.

A possible solution (suggested also by others in the comments) is to migrate your data to another format. Steps to achieve it:

  1. Deserialize your legacy contents with BinaryFormatter (you need to do it only once)
  2. Serialize them again with another serializer. I already mentioned a possible alternative that supports also ConcurrentDictionary<TKey, TValue> natively, meaning, no assembly qualified names are stored for it. If I got it correctly, you want to serialize ConcurrentDictionary<string, DateTime> instances, which is completely supported without storing any type names.
  3. After the migration use your new serializer only.

Please also note that though ConcurrentDictionary<TKey, TValue> was serializable in .NET Framework by regular IFormatters, it is no longer the case in .NET [Core]. So even if you could find a 3rd party implementation it would most likely fail when used from .NET Standard 2.0.

12
JonasH On

I do not think any serializer will handle a concurrent dictionary out of the box. Many support the common collection types, like list, array, and dictionary. But ConcurrentDictionary is not a common collection type.

And as explained in my answer to your previous question, you are very unlikely to find another library that can deserialize existing data from BinaryFormatter.

When serializing data it is usually a good practice to create types specifically for serialization. Often called Data Transfer Objects (DTO). Typically these need:

  1. Public setters for all properties
  2. public parameterless constructor
  3. Attributes, some libraries uses an opt-out model, while some use an opt-in model.

That increases flexibility since it can make it easier to deal with changes in format, and separates the serialization concern from any logic.

So start by converting your concurrent dictionary to a regular dictionary. If you really want to handle concurrentDictionaries, many libraries allow for some form of converters to allow you to specify how to serialize/deserialize custom types outside of your control.

I would also recommend following examples on how to serialize/deserialize objects. All of the libraries you listed should have fairly good documentation, including samples, etc.