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是另一个值
现在我想到了几个问题:
我已经尝试将
PublicKeyToken=null
更改为PublicKeyToken=123456789
,但这只是抛出了一个SerializationException
,表示没有有效的BinaryHeader
或对象版本已更改。Strong命名的程序集是不同的程序集(因为具有不同公钥的程序集实际上是不同的程序集)
考虑到这一点,更合理的做法是不能加载它们而不是预期的,因为默认情况下,BinaryFormatter
将尝试加载所需的程序集
您可以做的是创建SerializationBinder
,从当前执行的程序集中用PublicKey
替换nullPublicKey
。您的自定义序列化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() };
}