0

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

Vivek Nuna
  • 25,472
  • 25
  • 109
  • 197
  • 1
    Can't you deserialize the data with BinaryFormatter and then serialize it with another serializer? – shingo Aug 23 '23 at 08:38
  • 1
    "I now want to deserialize the content of the file using some other serializer." No, you shouldn't expect to be able to deserialize a file created with BinarySerializer using a different serializer - that's like asking `XDocument.Load` to handle a JSON file. – Jon Skeet Aug 23 '23 at 09:17
  • Have seen mail from you (via mobile app notifications) but can't access mailbox right now =( – Guru Stron Sep 01 '23 at 12:36
  • 1
    @GuruStron It was just a congratulatory message for achieving 1 million :).. you are a role model – Vivek Nuna Sep 01 '23 at 12:37
  • @VivekNuna *100k =) Thank you for the kind words! – Guru Stron Sep 01 '23 at 12:40

2 Answers2

4

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.

JonasH
  • 28,608
  • 2
  • 10
  • 23
  • While it is a good answer I believe you missed `so now I want to deserialize the content of the file using some other serializer.` - there frankly is no other serializer that can be used to deserialize the EXISTING data (which was once written using binary formatter) – Rand Random Aug 23 '23 at 08:00
  • 2
    @RandRandom I added a paragraph about that, second from the top. – JonasH Aug 23 '23 at 08:02
  • @JonasH Thank you for your answer, I also tried Dictionary in place of ConcurrentDictionary and used protobuf. But it also has the same issue. – Vivek Nuna Aug 23 '23 at 08:05
  • @VivekNuna Then create a question asking about *that*. **including examples of what you are doing**. Protobuf.net supports dictionaries out of the box. So you are either using the google protobuf library that might need extra work to map classes to .proto files, or doing something wrong. – JonasH Aug 23 '23 at 08:12
  • @JonasH I am using protobuf-net – Vivek Nuna Aug 23 '23 at 08:16
  • But as @RandRandom mentioned, I also think that its not possible at all. – Vivek Nuna Aug 23 '23 at 08:17
  • 1
    The issue OP is facing with protobuf is unrelated to concurrent dictionary. I tried to replicate the issue with the missing dependency of System.Memory, but in a new project it works as expected. So, the issue as was mentioned in previous question comment seems to be something only local on OPs solution/project. – Rand Random Aug 23 '23 at 08:19
  • @VivekNuna As mentioned in the previous question. You cannot use Protobuf.net, or any other library, to deserialize data that was serialized with BinaryFormatter. You should be able to use protobuf.net to serialize objects, and deserialize data that was serialized using protobuf.net. As long as you follow the rules for how data should be serialized. If you cannot get that to work, ask a new question, and include any details about project structure, library versions, objects etc. – JonasH Aug 23 '23 at 08:24
  • 2
    what I am saying should be rather obvious you can’t mix different serializers basic example would be you can’t serialize data as xml, and than decide from now on I want to use json, and the json serializer needs to be able to read the xml data - that’s just plain not possible you need to migrate old data first – Rand Random Aug 23 '23 at 08:25
  • @RandRandom yes, I was getting that System.Memory exception on my legacy project. this time I am trying a new .net 6 project. It's not giving this exception. But a different exception. – Vivek Nuna Aug 23 '23 at 08:33
  • @JonasH I agree with both of you guys, that is why I have planned to fix this problem in two releases. In the first release, I will just create an equivalent JSON/XML file. so that I will not lose any data. and in the second release, I will completely get rid of the BinaryFormatter code and use the XML/JSON serializer. But there is a problem with this approach if users don't upgrade to version 1.1, they directly upgrade to 1.2. – Vivek Nuna Aug 23 '23 at 08:36
  • so to overcome this issue I have come up with a design, I am adding that yo my question, please have a look. @RandRandom – Vivek Nuna Aug 23 '23 at 08:38
2

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.

György Kőszeg
  • 17,093
  • 6
  • 37
  • 65