Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Problems deserializing binary created with .NET Framework in .NET Core 3

Good day,

I tried to port a .NET Framework console app to .NET Core 3.0. But when I start the Core version I get an exception at the point where a binary file is deserialized.
This binary file was created with object serialization in another .NET Framework program using the BinaryFormatter class.
To deserialize it I am referencing the DLL containing the serialized class. So the code snipped from the console app is:

        IFormatter formatter = new BinaryFormatter();
        Stream stream = new FileStream(fileName, FileMode.Open, FileAccess.Read, FileShare.Read);
        EthCatalog = (EthernetCatalog)formatter.Deserialize(stream);

Where EthernetCatalog comes form the referenced DLL. And the exception I get is:

System.Runtime.Serialization.SerializationException: 'Type 'System.Net.IPAddress' in Assembly 'System.Net.Primitives, Version=4.1.1.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a' is not marked as serializable.'

so apparently somewhere in the EthernetCatalog class IPAddress class is used. This class is serializable in .NET Framework but not in .NET Core.

So my first question is can you make this work? Can I deserialize the file containing the EthernetCatalog object in .NET Core although the EthernetCatalog class is defined in a .NET Framework DLL? Like tell the Deserilized just to set everything to null that cannot be deserialized?

When investigating the problem I got actually more confused and more questions came up:

  1. Why is the .NET Framework DLL containing the EthernetCatalog class even using the IPAddress class from .NET Core?
    I would have expected when referencing .NET Framework DLLs in .NET Core that the .NET Framework DLLs are still using … well, the .NET Framework versions of all .NET classes.
  2. Is the attribute [System.Serializable] not used anymore in .NET Core?
    When I look at the MS .net documentation at https://learn.microsoft.com/en-us/dotnet/standard/serialization/binary-serialization there is a list of classes that can be used with BinaryFormatter. And every class in this list did not use the attribute [System.Serializable] when looking at the .NET Core documentation. But the attribute [System.Serializable] IS used for all these classes (that I checked) when switching to the .NET Framework documentation.

Thanks a lot in advance!

like image 861
Moritz Nadler Avatar asked Nov 07 '25 06:11

Moritz Nadler


1 Answers

  1. Why is the .NET Framework DLL containing the EthernetCatalog class even using the IPAddress class from .NET Core?

It doesn't. .NET has a type forwarding feature that makes possible to resolve types with their legacy .NET Framework identity. Feel free to check the .NET Core assemblies (the path is something like C:\Program Files\dotnet\shared\Microsoft.NETCore.App\3.0.0), you will find the System.dll even in .NET Core (where IPAddress resided in .NET Framework). But try to disassembly it and you will see that it does not contain any types but a bunch of assembly attributes. Among others:

[assembly: TypeForwardedTo(typeof(IPAddress))]

where IPAddress references the new place of the type in the System.Net.Primitives assembly. That's why you get the error message for the new identity.

  1. Is the attribute [System.Serializable] not used anymore in .NET Core?

It is, but many class that were serializable in .NET Framework are not serializable anymore in .NET Core (delegates, types, reflection members, streams, encoding, culture info, etc.). Ironically enough, the type forwarding mechanism is to support serialization, specifically BinaryFormatter mechanisms but it seems there are some types, which are not serializable anymore and they are still forwarded.

Possible solutions:

As a rule of thumb if you need to serialize objects across platforms you should prefer some text-based serialization such as XML or JSON.

But even if you really need to deserialize a legacy stream with BinaryFormatter there are some possible workarounds.

  1. Set the SurrogateSelector property of the BinaryFormatter to customize the deserialization of some types. Maybe the easiest solution if you use my CustomSerializerSurrogateSelector, which is exactly for this purpose. From its documentation:
// deserializing a MemoryStream in .NET Core that was serialized in .NET Framework
var formatter = new BinaryFormatter { SurrogateSelector = new CustomSerializerSurrogateSelector() };
var memoryStream = (MemoryStream)formatter.Deserialize(streamSerializedInNetFramework);

As you see I used it for MemoryStream but it should work the same way for IPAddress as well. You can download the library from nuget

  1. Another solution is to use a SerializationBinder that has to be assigned to the Binder property of the binary formatter: Redirect the IPAddress to a custom serializable class, which should implement IObjectReference. You have to implement the GetRealObject method, which must return a proper IPAddress instance.
like image 51
György Kőszeg Avatar answered Nov 08 '25 20:11

György Kőszeg



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!