Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/.net/22.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# BinaryFormatter上的TargetInvocationException。在向程序集添加强命名后反序列化_C#_.net_Serialization_Strongname - Fatal编程技术网

C# BinaryFormatter上的TargetInvocationException。在向程序集添加强命名后反序列化

C# BinaryFormatter上的TargetInvocationException。在向程序集添加强命名后反序列化,c#,.net,serialization,strongname,C#,.net,Serialization,Strongname,我使用BinaryFormatter.Serialize()和BinaryFormatter.Deserialize()和BinaryFormatter.Deserialize()编写了一个DLL,使用Save()和Load()方法将列表保存或加载到我计算机上的文件中 在我决定将强命名添加到程序集之前,这种方法一直很有效。一旦我在编译过程中添加了一个具有强名称的密钥,我的程序就无法再加载强名称前的命名文件。我得到了一个targetingException,其中FileLoadException作

我使用
BinaryFormatter.Serialize()
BinaryFormatter.Deserialize()
BinaryFormatter.Deserialize()
编写了一个DLL,使用
Save()
Load()
方法将
列表
保存或加载到我计算机上的文件中

在我决定将强命名添加到程序集之前,这种方法一直很有效。一旦我在编译过程中添加了一个具有强名称的密钥,我的程序就无法再加载强名称前的命名文件。我得到了一个
targetingException
,其中
FileLoadException
作为
InnerException
表示未找到
MyAssembly,Version=1.0.1.0,Culture=neutral,PublicKeyToken=null

当我用十六进制编辑器打开文件时,我可以在文件中看到对我的程序集的多个引用:
MyAssembly,Version=1.0.1.0,Culture=neutral,PublicKeyToken=null

当我用新的强名称程序集保存文件时,有一件事发生了变化:
PublicKeyToken=123456789
。当然,其中123456789是另一个值

现在我想到了几个问题:

  • 为什么保存文件时使用的Assemblyversion很重要
  • 如果我想写另一个程序,可以访问这些文件中的数据。。。这可能吗
  • 我是否可以转换预强命名文件,以便使用强命名程序集读取它们

  • 我已经尝试将
    PublicKeyToken=null
    更改为
    PublicKeyToken=123456789
    ,但这只是抛出了一个
    SerializationException
    ,表示没有有效的
    BinaryHeader
    或对象版本已更改。

    Strong命名的程序集是不同的程序集(因为具有不同公钥的程序集实际上是不同的程序集)

    考虑到这一点,更合理的做法是不能加载它们而不是预期的,因为默认情况下,
    BinaryFormatter
    将尝试加载所需的程序集

    您可以做的是创建
    SerializationBinder
    ,从当前执行的程序集中用
    PublicKey
    替换null
    PublicKey
    。您的自定义序列化binder可用于分配
    BinaryFormatter.binder
    属性

    var formatter = new BinaryFormatter { Binder = new MyCustomBinder() };
    
    其中
    MyCustomBinder
    为(仅相关部分):

    当然,您应该只为自己的程序集(而不是您不知道的任何其他类型)执行此操作,并且您应该仔细检查这是否会破坏应用程序的安全性

    编辑:请注意,某些类型使用序列化代理(例如
    MemberInfo
    MemberInfoSerializationHolder
    ).由于此代理而加载的类型将不会通过自定义序列化绑定。值得注意的是代理。是的,序列化代理不是一个好主意,我倾向于避免它(另请参见),但如果必须使用它,则还需要处理
    AppDomain.CurrentDomain.AssemblyResolve
    事件(使用与上述相同的逻辑):在反序列化之前附加处理程序,并在完成后将其删除;理想情况下,您可以在序列化绑定器中执行所有操作:

    sealed class MyCustomBinder : SerializationBinder, IDisposable
    {
        public MyCustomBinder()
        {
            AppDomain.CurrentDomain.AssemblyResolve += OnAssemblyResolve;
        }
    
        void IDisposable.Dispose()
        {
            AppDomain.CurrentDomain.AssemblyResolve -= OnAssemblyResolve;
        }
    
        // Your code here
    }
    
    用法如下:

    using (var binder = new MyCustomBinder())
    {
        var formatter = new BinaryFormatter { Binder = new MyCustomBinder() };
    }
    

    注意:我没有尝试过,但是如果您需要使用
    AppDomain.AssemblyResolve
    ,那么您甚至不需要自定义活页夹,一切都可以在那里完成…

    可以与
    type.GetType()
    一起使用的完整类型名称(带程序集)。例如:
    返回类型.GetType(String.Format(“{0},{1}”,typeName,name.ToString())59[[MyClass,MyNamespace,Version=2.0.2.0,Culture=neutral,PublicKeyToken=null]
    ->什么都没有发生。我仍然会收到错误。最后一段:u“当然,您应该只为自己的程序集执行此操作…”。该代码仅适用于您自己的程序集!因此,由于我序列化了一个
    列表
    ,而不仅仅是
    MyObject
    ,所以这种方法对我不起作用,对吗?是的,已经放弃了它。下一步是使用BinaryFormatter;)
    using (var binder = new MyCustomBinder())
    {
        var formatter = new BinaryFormatter { Binder = new MyCustomBinder() };
    }