简体   繁体   English

.Net二进制反序列化

[英].Net Binary Deserialization

I am using BinaryFormatter to deserialize a file from another application. 我正在使用BinaryFormatter从另一个应用程序反序列化文件。 They share base libraries and most of the types serialized in the file are known. 它们共享基本库,并且文件中序列化的大多数类型都是已知的。

However, there are also some types completely unknown and without no updatable match. 但是,也有一些类型完全未知,没有可更新的匹配。 I want to be able to discard deserialization for those cases. 我希望能够为这些案例丢弃反序列化。

Currently I am using a BinaryFormatter initialized with a SurrogateSelector and a SerializationBinder that I use to update to types affected by namespace changes in recent versions. 目前我使用的是使用SurrogateSelector和SerializationBinder初始化的BinaryFormatter,我用它来更新最近版本中受命名空间更改影响的类型。

var formatter = new BinaryFormatter
{
    Context = streamingContext,
    SurrogateSelector = ss,
    Binder = new ProxiedRemappingSerializationBinder(),
    FilterLevel = TypeFilterLevel.Low
};

try
{
    var deserializedObject = formatter.Deserialize(contentsStream);
    ...
}

Specifically, the problem arises when, internally, the .NET Framework's tries to set values on an array of a known interface, but with unknown value type. 具体来说,问题出现在.NET Framework内部尝试在已知接口的数组上设置值但具有未知值类型时。 The exception I get is: "System.InvalidCastException: Object cannot be stored in an array of this type." 我得到的例外是:“System.InvalidCastException:Object不能存储在这种类型的数组中。”

So is there any way of making deserialization process discard these types (and just leave nulls) or even acting on the SerializationBinder somehow to prevent this exception? 那么是否有任何方法可以使反序列化过程丢弃这些类型(并且只留下空值)甚至以某种方式对SerializationBinder进行操作以防止此异常?

Thanks in advance 提前致谢

** EDIT ** **编辑**

Besides the stack trace, the error is the typical InvalidcastException. 除了堆栈跟踪之外,错误是典型的InvalidcastException。 I debugged within the .NET Framework, going through BinaryFormatter, BinaryObjectReader and ObjectManager, and it fails on the fixup phase (when it is assigning the actual values to the instances) on an array. 我在.NET Framework中调试,通过BinaryFormatter,BinaryObjectReader和ObjectManager,它在阵列上的修复阶段(当它为实例分配实际值时)失败。 Breaking in Array.cs, line 516, in InternalSetValue(&elemref,value); 在InternalSetValue(&elemref,value)中打破Array.cs,第516行; is where the exception gets raised. 是引发异常的地方。

I am using the Binder to change some types in de-serialization time to ones that my application knows (more recent version of the type), or to a dummy class. 我正在使用Binder将反序列化时间中的某些类型更改为我的应用程序知道的类型(更新版本的类型),或者更改为虚拟类。 I understand why the exception happens, basically it is trying to set an incompatible object type on an interface array. 我理解为什么异常发生,基本上它试图在接口数组上设置不兼容的对象类型。

This type is a proxy type I dynamically generated to hold object info similar to this implementation: http://holistictendencies.wordpress.com/2009/11/16/creating-proxies-in-for-round-tripping-unknown-objects-in-c-server-apps/ So, since it doesn't implement the array interface, it fails. 此类型是我动态生成的代理类型,用于保存与此实现类似的对象信息: http//holistictendencies.wordpress.com/2009/11/16/creating-proxies-in-for-round-tripping-unknown-objects- in-c-server-apps /因此,由于它没有实现阵列接口,因此失败了。 I just want the engine to discard these cases somehow. 我只是希望引擎以某种方式丢弃这些案例。

I had a similar issue where I needed to BinaryFormatter.Deserialize() a class that I didn't have type information for but wanted to get some of the values from the properties from that object. 我有一个类似的问题,我需要BinaryFormatter.Deserialize()一个我没有类型信息但希望从该对象的属性中获取一些值的类。

When it came time to deserialize that object .NET was throwing a SerializationException, complaining about the unknown assembly type. 当反序列化该对象时,.NET抛出了SerializationException,抱怨未知的程序集类型。

I solved it by creating a custom class with the properties I needed (marked as Serializable) and then created another class that inherits from SerializationBinder: 我通过创建一个具有我需要的属性的自定义类(标记为Serializable)来解决它,然后创建另一个继承自SerializationBinder的类:

public class MySerializationBinder : SerializationBinder
{
    public override Type BindToType(string assemblyName, string typeName)
    {
        if (assemblyName.Contains("namespace I don't have") && typeName.Contains("type info I don't have"))
                return typeof(MySubstitute);
        return Type.GetType($"{typeName}, {assemblyName}");
    }
}

[Serializable]
public class MySubstitute
{
    public string Name { get; set; }
    public string Title { get; set; }
}

Notice how if it isn't the type I am looking for I just return what was passed in. 请注意如果它不是我正在寻找的类型我只返回传入的内容。

Then when you create your BinaryFormatter set the binder property to an instance of your new custom binder: 然后,当您创建BinaryFormatter时,将binder属性设置为新自定义绑定器的实例:

 using (FileStream fs = new FileStream(openFileDialog1.FileName, FileMode.Open))
 {
       BinaryFormatter bf = new BinaryFormatter()   
      {
            Binder = new MySerializationBinder ()
       };                     
       mySubstitute = (MySubstitute)bf.Deserialize(fs);           
       fs.Close();
 }

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM