Проблемы десериализации двоичного файла, созданного с помощью. NET Framework in. NET Core 3 - PullRequest
1 голос
/ 27 апреля 2020

Добрый день,

Я попытался перенести консольное приложение. NET Framework на. NET Core 3.0. Но когда я запускаю версию Core, я получаю исключение в момент десериализации двоичного файла.
Этот двоичный файл был создан с сериализацией объекта в другой. NET Программа Framework, использующая класс BinaryFormatter.
Для десериализации я ссылаюсь на DLL, содержащую сериализованный класс. Таким образом, код, извлеченный из консольного приложения:

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

Где EthernetCatalog приходит из указанной библиотеки DLL. И я получаю исключение:

System.Runtime.Serialization.SerializationException: 'Тип' System. Net .IPAddress 'в сборке' System. Net .Primitives, Version = 4.1. 1.0, Culture = нейтральный, PublicKeyToken = b03f5f7f11d50a3a 'не помечен как сериализуемый.'

, поэтому очевидно, что где-то в классе EthernetCatalog используется класс IPAddress. Этот класс можно сериализовать в. NET Framework, но не в. NET Core.

Итак, мой первый вопрос: можете ли вы сделать эту работу? Можно ли десериализовать файл, содержащий объект EthernetCatalog в. NET Core, хотя класс EthernetCatalog определен в. NET Framework DLL? Например, сказать «Пустыням» просто установить все в нуль, что нельзя десериализовать?

При исследовании проблемы я действительно запутался, и возникло больше вопросов:

  1. Почему . NET Framework DLL, содержащая класс EthernetCatalog, даже используя класс IPAddress из. NET Core?
    Я бы ожидал при ссылках. NET Framework DLL в. NET Ядро, что. NET Framework DLL все еще используют ... ну,. NET версии Framework всех. NET классов.
  2. Не используется ли атрибут [System.Serializable] в. NET Core?
    Когда я смотрю на документацию MS. net в https://docs.microsoft.com/en-us/dotnet/standard/serialization/binary-serialization, есть список классов, которые можно использовать с BinaryFormatter. И каждый класс в этом списке не использовал атрибут [System.Serializable] при просмотре. NET базовой документации. Но атрибут [System.Serializable] используется для всех этих классов (которые я проверял) при переходе на документацию. NET Framework.

Заранее большое спасибо!

1 Ответ

1 голос
/ 27 апреля 2020
  1. Почему DLL-библиотека. NET Framework содержит класс EthernetCatalog, даже используя класс IPAddress из. NET Core?

Это не так , . NET имеет функцию пересылки типов, которая позволяет разрешать типы с их унаследованными. Не стесняйтесь проверять сборки ядра. NET (путь примерно такой же, как C:\Program Files\dotnet\shared\Microsoft.NETCore.App\3.0.0), вы найдете System.dll даже в. NET ядре (где IPAddress находился в. NET Framework). Но попробуйте разобрать его, и вы увидите, что он не содержит никаких типов, но содержит набор атрибутов сборки. Среди прочего:

[assembly: TypeForwardedTo(typeof(IPAddress))]

, где IPAddress указывает на новое место типа в сборке System.Net.Primitives. Вот почему вы получаете сообщение об ошибке для новой личности.

Не используется ли атрибут [System.Serializable] в. NET Core?

Да, но многие классы, которые были сериализуемы в. NET Framework больше не сериализуются в. NET Ядро (делегаты, типы, члены отражения, потоки, кодирование, культура) info, et c.). Как ни странно, механизм пересылки типов должен поддерживать сериализацию, в частности механизмы BinaryFormatter, но, похоже, есть некоторые типы, которые больше не сериализуются, и они все еще пересылаются.

Возможные решения:

Как правило, если вам нужно сериализовать объекты на разных платформах, вы должны предпочесть некоторую текстовую сериализацию, такую ​​как XML или JSON.

Но даже если вам действительно нужно для десериализации унаследованного потока с помощью BinaryFormatter возможны некоторые обходные пути.

  1. Установите свойство SurrogateSelector BinaryFormatter, чтобы настроить десериализацию некоторых типов. Возможно, самое простое решение, если вы используете мой CustomSerializerSurrogateSelector , который предназначен именно для этой цели. Из документации:
// 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);

Как вы видите, я использовал его для MemoryStream, но он должен работать так же и для IPAddress. Вы можете скачать библиотеку с nuget

Другое решение заключается в использовании SerializationBinder, который должен быть присвоен свойству Binder двоичного форматера: перенаправьте IPAddress в настраиваемый сериализуемый класс, который должен реализовывать IObjectReference. Вы должны реализовать метод GetRealObject, который должен возвращать правильный экземпляр IPAddress.
...