Mat*_*ith 3 c# serialization .net-assembly
在Suzanne Cook的.NET CLR Notes中,她谈到了“ LoadFrom”上下文的危险。特别,
- 如果Load上下文程序集尝试按显示名称加载此程序集,则默认情况下将找不到它(例如,当mscorlib.dll反序列化此程序集时)
- 更糟糕的是,在探测路径上可能会找到具有相同标识但路径不同的程序集,从而导致稍后导致InvalidCastException,MissingMethodException或意外的方法行为。
如何在不显式加载程序集的两个不同版本的情况下通过反序列化来重现此行为?
我创建了一个控制台应用程序A.exe,该应用程序通过类库B.dll间接加载(通过`Assembly.LoadFrom)并调用(通过反射)代码。
Assembly.LoadFrom。可执行文件
class Program
{
static void Main(string[] args)
{
// I have a post build step that copies the B.dll to this sub directory.
// but the B.dll also lives in the main directory alongside the exe:
// mkdir LoadFrom
// copy B.dll LoadFrom
//
var loadFromAssembly = Assembly.LoadFrom(@".\LoadFrom\B.dll");
var mySerializableType = loadFromAssembly.GetType("B.MySerializable");
object mySerializableObject = Activator.CreateInstance(mySerializableType);
var copyMeBySerializationMethodInfo = mySerializableType.GetMethod("CopyMeBySerialization");
try
{
copyMeBySerializationMethodInfo.Invoke(mySerializableObject, null);
}
catch (TargetInvocationException tie)
{
Console.WriteLine(tie.InnerException.ToString());
}
Console.ReadKey();
}
}
Run Code Online (Sandbox Code Playgroud)
B.dll
namespace B
{
[Serializable]
public class MySerializable
{
public MySerializable CopyMeBySerialization()
{
return DeepClone(this);
}
private static T DeepClone<T>(T obj)
{
using (var ms = new MemoryStream())
{
var formatter = new BinaryFormatter();
formatter.Serialize(ms, obj);
ms.Position = 0;
return (T)formatter.Deserialize(ms);
}
}
}
}
Run Code Online (Sandbox Code Playgroud)
输出量
System.InvalidCastException:
[A]B.MySerializable cannot be cast to
[B]B.MySerializable.
Type A originates from 'B, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null'
in the context 'Default' at location 'c:\Dev\bin\Debug\B.dll'.
Type B originates from 'B, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null'
in the context 'LoadFrom' at location 'c:\Dev\bin\Debug\LoadFrom\B.dll'.
at B.MySerializable.DeepClone[T](T obj)
at B.MySerializable.CopyMeBySerialization()
Run Code Online (Sandbox Code Playgroud)
这是正在发生的事情:
formatter.Deserialize(ms),它将使用MemoryStream中存储的信息来确定需要创建哪种类型的对象(以及创建该对象所需的程序集)。 (T)formatter.Deserialize(ms)失败。附加条款:
Assembly.Load,则将InvalidCastException出现SerializationException,提示消息“ 无法找到程序集'B,Version = 1.0.0.0,Culture = neutral,PublicKeyToken = null”。 '。DeepClone我显示的代码似乎是在对象上进行深度克隆的较流行的方法之一。请参阅:在C#中深度克隆对象。因此,从任何已加载到“ LoadFrom”上下文中的代码中,您都无法成功使用反序列化(必须跳过附加箍以允许程序集在默认的“ Load”上下文中成功加载)。