1

I'm migrating a set of applications from .Net Framework 4.7 to .Net 5.0, but I'm running into some issues with deserializion.

The example below illustrates the problem I'm facing. If both applications are .Net framework, it works fine. If both are .Net 5.0, it works fine. But if one application is .Net 4.7 and the other is 5.0, I get an exception when deserializing the type List<IList>.

.Net 5.0 application CreateData:

using System;
using System.Collections;
using System.IO;
using System.Runtime.Serialization.Formatters.Binary;
using Test;

namespace CreateData
{
    class Program
    {
        static void Main()
        {
            DataStructure dataStructure = new DataStructure();

            ArrayList arrayList = new ArrayList();
            arrayList.Add(42);
            dataStructure.data.Add(arrayList);

            // Open a stream for writing
            FileStream fs = new FileStream(@"C:\DataFile.dat", FileMode.Create);
            
            BinaryFormatter bf = new BinaryFormatter();
            bf.Serialize(fs, dataStructure);
            fs.Close();

            Console.WriteLine("Data file created, press Enter to exit");
            Console.ReadLine();
        }
    }
}

.Net Standard 2.0 library Lib:

using System;
using System.Collections;
using System.Collections.Generic;

namespace Test
{
    [Serializable]
    public class DataStructure
    {
        public DataStructure()
        {
            data = new List<IList>();
        }

        public List<IList> data;
    }
}

.Net 4.7 application ReadData:

using System;
using System.Linq;
using System.IO;
using System.Runtime.Serialization.Formatters.Binary;
using Test;


namespace ReadData
{
    class Program
    {
        static void Main()
        {
            DataStructure dataStructure = new DataStructure();

            // Open the data file
            FileStream fs =  new FileStream(@"C:\DataFile.dat",FileMode.Open);

            // Construct the binary formatter
            BinaryFormatter bf = new BinaryFormatter();
            
            // deserialize
            dataStructure = (DataStructure) bf.Deserialize(fs);
            fs.Close();

            // Announce success
            Console.WriteLine("Value = {0}", dataStructure.data.First()[0]);
            Console.WriteLine("Press enter to exit");
            Console.ReadLine();
        }
    }
}

System.Runtime.Serialization.SerializationException: Unable to load type System.Collections.Generic.List`1[[System.Collections.IList, System.Private.CoreLib, Version=5.0.0.0, Culture=neutral, PublicKeyToken=7cec85d7bea7798e]] required for deserialization. at System.Runtime.Serialization.ObjectManager.CompleteObject(ObjectHolder holder, Boolean bObjectFullyComplete) at System.Runtime.Serialization.ObjectManager.DoNewlyRegisteredObjectFixups(ObjectHolder holder) at System.Runtime.Serialization.ObjectManager.RegisterObject(Object obj, Int64 objectID, SerializationInfo info, Int64 idOfContainingObj, MemberInfo member, Int32[] arrayIndex) at System.Runtime.Serialization.Formatters.Binary.ObjectReader.RegisterObject(Object obj, ParseRecord pr, ParseRecord objectPr, Boolean bIsString) at System.Runtime.Serialization.Formatters.Binary.ObjectReader.RegisterObject(Object obj, ParseRecord pr, ParseRecord objectPr) at System.Runtime.Serialization.Formatters.Binary.ObjectReader.ParseObjectEnd(ParseRecord pr) at System.Runtime.Serialization.Formatters.Binary.ObjectReader.Parse(ParseRecord pr) at System.Runtime.Serialization.Formatters.Binary.__BinaryParser.Run()
at System.Runtime.Serialization.Formatters.Binary.ObjectReader.Deserialize(HeaderHandler handler, __BinaryParser serParser, Boolean fCheck, Boolean isCrossAppDomain, IMethodCallMessage methodCallMessage) at System.Runtime.Serialization.Formatters.Binary.BinaryFormatter.Deserialize(Stream serializationStream, HeaderHandler handler, Boolean fCheck, Boolean isCrossAppDomain, IMethodCallMessage methodCallMessage) at System.Runtime.Serialization.Formatters.Binary.BinaryFormatter.Deserialize(Stream serializationStream, HeaderHandler handler, Boolean fCheck, IMethodCallMessage methodCallMessage) at System.Runtime.Serialization.Formatters.Binary.BinaryFormatter.Deserialize(Stream serializationStream, HeaderHandler handler, Boolean fCheck) at System.Runtime.Serialization.Formatters.Binary.BinaryFormatter.Deserialize(Stream serializationStream, HeaderHandler handler) at System.Runtime.Serialization.Formatters.Binary.BinaryFormatter.Deserialize(Stream serializationStream) at ReadData.Program.Main() in

Is there any way to load the type System.Collections.Generic.List1[[System.Collections.IList, System.Private.CoreLib, Version=5.0.0.0, Culture=neutral, PublicKeyToken=7cec85d7bea7798e]]? What can I do to resolve this?

If at all possible, I would like to migrate one application at a time instead of migrating the entire code base in one go.

Thanks!

Q-bertsuit
  • 3,223
  • 6
  • 30
  • 55
  • Maybe you need to change the binder like this answer: https://stackoverflow.com/a/7154652/1724128 – Leo Sep 23 '21 at 11:21
  • 2
    Honestly, BinaryFormatter is just going to keep hurting you; it is *effectively* obsoleted and deprecated now; is changing the serializer an option? – Marc Gravell Sep 23 '21 at 11:26
  • 1
    Part of the migration is probably going to have to be moving away from this kind of serialization; it may be worth sticking to .NET Framework while you do that so the transition is that much smoother. – Jeroen Mostert Sep 23 '21 at 11:35
  • @JeroenMostert Exactly. There are so many loose ends already, so I would really prefer not to change serialization just yet (although I agree it needs to be done eventually) – Q-bertsuit Sep 23 '21 at 11:52
  • Well, my argument would be that while you are busy *not* changing the serialization, you should probably also be busy *not* migrating to .NET 5. :) Remember, .NET Framework will be supported for quite a while to come, and despite all the work that's been put in, for some projects it just won't be a drop-in upgrade. Binary serialization is definitely one of those areas that's badly affected; Microsoft would really like to move on from this altogether, so prepare to move on with them. Cross-framework compatibility is never going to make the feature list. – Jeroen Mostert Sep 23 '21 at 11:56
  • I actually did spend some time trying to change the serialization already. I've tried different kinds of XML and JSON, but the objects we are serializing are complete beasts and I ran into all sorts of issues. It feels like I've been swimming over a vast ocean, and finally I see a small island where I can stop and rest. If only I can manage to deserialize List. Even though it's a detour to reach the island, I still prefer it to swimming the entire distance in one go. I could potentially do all this work and change serialization only to find out that nothing works anymore – Q-bertsuit Sep 23 '21 at 12:17

1 Answers1

3

Congratulations! You have found one of the reason not to use BinaryFormatter. Other reasons include safety, performance and size. I would recommend to switch to just about anything else as soon as possible.

The recommended way to manage serialization is to separate the types used for serialization from the types that contain actual logic. This allow the respective types to be adapted for the respective purpose. Things like backward compatibility is simpler since things like adding properties are usually possible, and you have the option to keep multiple versions of the same type in case there are larger changes in the type structure.

I would also highly recommend setting up unit tests, to test that different types serializes/deserializes correctly. But unit tests are often also a very useful tool to learn what is possible or not with a serialization library.

You might be able to do something like type-mapping, but that is a huge cludge in my opinion. It might also help to change types to something like arrays instead of lists, but if you are changing the serialization format you are probably better of switching to something better. It might be possible to write a converter in .net 4.7 to convert between the old format and a newer format.

JonasH
  • 28,608
  • 2
  • 10
  • 23