.Net 二进制反序列化运行时平台的故障检测/取证

发布于 2024-09-09 09:52:27 字数 2042 浏览 0 评论 0原文

我正在寻找有关如何检测运行时平台以公开 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) 

I'm looking for insight on how to instrument a runtime platform to expose the source type of a Microsoft .Net binary deserialization failure.

When using BinaryFormatter.Deserialize(StreamingContextStates.CrossMachine) and one of the types does not exist in the current binaries; instead of throwing an error, .Net inserts the object [TypeLoadExceptionHolder]. Particularly for collections, this causes no immediate problem.

Subsequently when the collection is serialized for transmission between application tiers; the platform receives a 'serialization failure' because [TypeLoadExceptionHolder] cannot be serialized. So the resulting error is useless for actually providing clues as to the source-type that caused the problem. Now the hunt (time suck) is on to see which developer (of hundreds) added a new type to a million-line platform.

This problem happens with some frequency because of the serialization stream used to support the platform sessioncache. Code is deployed fairly often and in an incremental fashion. Customer page-requests can bounce between old and new versions of the codebase during the deployment window. Careless introduction of a new type will cause the page-requests on the old version to blow up.

Any thoughts about providing runtime rich error/trap would be appreciated.


(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) 

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

在巴黎塔顶看东京樱花 2024-09-16 09:52:27

那么,您可以采取的一种方法是使用自定义 < code>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();

Well, one approach you could take is to use a custom SerializationBinder that overrides BindToType and checks the type name during deserialization.

Depending on what you'd like to accomplish, when you identify an unknown type you could either:

  • Raise an Exception (Pessimistic): Catch the issue early on and can easily identity the type with a custom message or exception.

  • Log the Type Name (Optimistic): If there are scenarios where unknown types are OK, logging would provide the details necessary to diagnose exceptions if they occur later during serialization.

You could also select a different approach depending on characteristics of the type name (i.e. if the type appears to be part of your application or part of a 3rd party library).

The TypeLoadExceptionHolder instance created during deserialization does contain a non-public member TypeName that contains the name of the type that could not be resolved. However, the instance is not available from the SerializationException you encounter later on, and even so, the value would only be available via reflection in trusted contexts.

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();
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文