Подтвердить что ты не робот

.Net Двойная десериализация. Обнаружение сбоев/криминализация платформы времени выполнения.

Я ищу информацию о том, как настроить платформу времени выполнения, чтобы выявить исходный тип сбоя двоичной десериализации Microsoft.Net.

При использовании BinaryFormatter.Deserialize(StreamingContextStates.CrossMachine) и один из типов не существует в текущих двоичных файлах; вместо того, чтобы бросать ошибку,.Net вставляет объект [TypeLoadExceptionHolder]. В частности, для коллекций это не вызывает непосредственной проблемы.

Впоследствии, когда сборник сериализуется для передачи между уровнями приложений; платформа получает "сбой сериализации", потому что [TypeLoadExceptionHolder] не может быть сериализована. Таким образом, полученная ошибка бесполезна для фактического предоставления подсказок относительно типа источника, вызвавшего проблему. Теперь идет охота (время сосать), чтобы узнать, какой разработчик (из сотен) добавил новый тип к платформе с миллионами строк.

Эта проблема возникает с некоторой частотой из-за потока сериализации, используемого для поддержки сеанса сеанса платформы. Код развертывается довольно часто и постепенно. Клиентские запросы могут отскакивать от старой и новой версий кодовой базы во время развертывания. Небрежное введение нового типа приведет к взрыву страниц-запросов в старой версии.

Понятно, что любые мысли о предоставлении ошибки/ловушки, зависящей от времени выполнения, будут оценены.


(SerializationException) 
Type 'System.Runtime.Serialization.TypeLoadExceptionHolder' in Assembly 'mscorlib, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089' is not marked as serializable. 
- at System.Runtime.Serialization.FormatterServices.InternalGetSerializableMembers(RuntimeType type) 
- at System.Runtime.Serialization.FormatterServices.GetSerializableMembers(Type type, StreamingContext context) 
- at System.Runtime.Serialization.Formatters.Binary.WriteObjectInfo.InitMemberInfo() 
- at System.Runtime.Serialization.Formatters.Binary.WriteObjectInfo.InitSerialize(Object obj, ISurrogateSelector surrogateSelector, StreamingContext context, SerObjectInfoInit serObjectInfoInit, IFormatterConverter converter, ObjectWriter objectWriter) 
- at System.Runtime.Serialization.Formatters.Binary.WriteObjectInfo.Serialize(Object obj, ISurrogateSelector surrogateSelector, StreamingContext context, SerObjectInfoInit serObjectInfoInit, IFormatterConverter converter, ObjectWriter objectWriter) 
- at System.Runtime.Serialization.Formatters.Binary.ObjectWriter.Write(WriteObjectInfo objectInfo, NameInfo memberNameInfo, NameInfo typeNameInfo) 
- at System.Runtime.Serialization.Formatters.Binary.ObjectWriter.Serialize(Object graph, Header[] inHeaders, __BinaryWriter serWriter, Boolean fCheck) 
- at System.Runtime.Serialization.Formatters.Binary.BinaryFormatter.Serialize(Stream serializationStream, Object graph, Header[] headers, Boolean fCheck) 
4b9b3361

Ответ 1

Ну, один из подходов, который вы можете сделать, - использовать SerializationBinder, который переопределяет BindToType и проверяет имя типа во время десериализации.

В зависимости от того, что вы хотели бы выполнить, когда вы идентифицируете неизвестный тип, вы можете:

  • Поднять исключение (пессимистично): уловить проблему на ранней стадии и легко идентифицировать тип с помощью специального сообщения или исключения.

  • Запишите имя типа (оптимистично): если есть сценарии, в которых неизвестные типы в порядке, регистрация обеспечит детали, необходимые для диагностики исключений, если они возникнут позже во время сериализации.

Вы также можете выбрать другой подход в зависимости от характеристик имени типа (т.е. если этот тип является частью вашего приложения или части библиотеки сторонних разработчиков).

Экземпляр TypeLoadExceptionHolder, созданный во время десериализации, содержит непубличный элемент TypeName, который содержит имя типа, который не может быть разрешен. Однако экземпляр недоступен из SerializationException, с которым вы столкнулись позже, и даже в этом случае значение будет доступно только через отражение в доверительных контекстах.

public class CustomSerializationBinder : SerializationBinder
{
    public override Type BindToType(string assemblyName, string typeName)
    {
        Type t = Type.GetType(string.Concat(typeName, ", ", assemblyName));

        if (t == null)
        {
            throw new SerializationException(string.Format("Type {0} from assembly {1} could not be bound.", typeName, assemblyName));
        }

        return t;
    }

    public override void BindToName(Type serializedType, out string assemblyName, out string typeName)
    {
        base.BindToName(serializedType, out assemblyName, out typeName);
    }
}

...

BinaryFormatter.Binder = new CustomSerializationBinder();