反序列化具有在 AssemblyResolve 上加载的其他程序集中声明的类型字段的对象时出错
Posted
技术标签:
【中文标题】反序列化具有在 AssemblyResolve 上加载的其他程序集中声明的类型字段的对象时出错【英文标题】:Error deserializing object having a field of type declared in the other assembly loaded on AssemblyResolve 【发布时间】:2011-05-19 08:31:05 【问题描述】:我有一个应用程序,它在自身内部嵌入(通过 BuildAction:嵌入式资源)引用的程序集(称为 ClassLibrary1)并将其加载到 AppDomain.CurrentDomain.AssemblyResolve 事件中。 主程序集定义了一个类 Class1:
public class Class1
public Class2 MyField get; set;
它具有在 ClassLibrary1 中定义的 Class2 类型的属性。 Class2的定义:
public class Class2
public int A get; set;
在主要方法中,我正在创建一个新的 XmlSerializer(typeof(Class1)):
static void Main()
SubscribeAssemblyResolver();
MainMethod();
private static void MainMethod()
XmlSerializer xs2 = new XmlSerializer(typeof(Class1));
Class1 cl = new Class1();
在执行程序时出现以下错误:
无法生成临时类(结果=1)。 错误 CS0012:“ClassLibrary1.Class2”类型在未引用的程序集中定义。您必须添加对程序集“ClassLibrary1,Version=1.0.0.0,Culture=neutral,PublicKeyToken=c06f123f2868e8c8”的引用。 错误 CS0266:无法将类型“object”隐式转换为“ClassLibrary1.Class2”。存在显式转换(您是否缺少演员表?)
有什么想法吗?
其余代码:
private static void SubscribeAssemblyResolver()
AppDomain.CurrentDomain.AssemblyResolve += new ResolveEventHandler(CurrentDomain_AssemblyResolve);
static Dictionary<String, Assembly> _assemblies = new Dictionary<String, Assembly>(StringComparer.OrdinalIgnoreCase);
static System.Reflection.Assembly CurrentDomain_AssemblyResolve(object sender, ResolveEventArgs args)
return ResolveAssembly(args.Name);
private static Assembly ResolveAssembly(string argsName)
Assembly dll;
var name = "WindowsFormsApplication1.Libs." + new AssemblyName(argsName).Name + ".dll";
if (!_assemblies.TryGetValue(name, out dll))
Assembly res = typeof(Program).Assembly;
using (var input = res.GetManifestResourceStream(name))
if (input == null)
//TODO: log
return null;
Byte[] assemblyData = new Byte[input.Length];
input.Read(assemblyData, 0, assemblyData.Length);
if (null == (dll = Assembly.Load(assemblyData)))
//TODO: log
return null;
//TODO: log
_assemblies[name] = dll;
return dll;
return dll;
更新:在 microsoft Connect 站点上创建了一个 BUG。您还可以从那里下载一个示例 visual stuido 2010 解决方案(只需展开详细信息字段组)以重现它。
【问题讨论】:
此错误不仅限于动态加载的程序集。见Error creating XML Serializer in specific situation in VB。不幸的是,除非对安全性至关重要,否则 XmlSerializer 错误不会得到修复。 感谢您的链接,约翰!不幸的是,在我的情况下,上述错误的解决方法中指定的解决方案不起作用: XmlSerializer xs2 = new XmlSerializer(typeof(Class1), new Type[] typeof(Class2) );我仍然遇到同样的错误。 好的,也许解决方法对您不起作用的原因是因为您的动态加载。作为一个实验,您可以尝试使用静态加载吗?1)查看是否仍然出现错误,以及 2)查看解决方法是否适用于静态加载。如果问题是动态加载,那么我建议你输入一篇新的 Connect 文章并在此处发布 URL。 @John:如果静态加载没有问题(例如 ClassLibrary1.dll 与 ConsoleApplication1 位于同一文件夹中,并通过标准 .net 机制加载)我创建了一个新的 Connect 错误并添加了一个vs2010解决方案,帖子中有一个链接。 【参考方案1】:我通过将程序集保存在临时文件夹中解决了类似的问题
public static byte[] ReadFully(Stream input)
var buffer = new byte[16 * 1024];
using (var ms = new MemoryStream())
int read;
while ((read = input.Read(buffer, 0, buffer.Length)) > 0)
ms.Write(buffer, 0, read);
return ms.ToArray();
public App()
AppDomain.CurrentDomain.AssemblyResolve += (sender, args) =>
var assemblyName = new AssemblyName(args.Name);
if (assemblyName.Name != "Omikad.Core")
return null;
var resourceName = "Terem." + assemblyName.Name + ".dll";
using (var stream = Assembly.GetExecutingAssembly().GetManifestResourceStream(resourceName))
if (stream == null)
return null;
var assemblyData = ReadFully(stream);
var tmp = Path.Combine(Path.GetTempPath(), "Omikad.Core.dll");
File.WriteAllBytes(tmp, assemblyData);
return Assembly.LoadFrom(tmp);
;
【讨论】:
【参考方案2】:尝试添加属性:
[XmlInclude(typeof(Class2))]
public class Class1
public Class2 MyField get; set;
【讨论】:
我已经试过了,还是不行,谢谢回复。【参考方案3】:就目前而言,我最终得到了两个有点糟糕的解决方案:
-
虽然您不能为 Class1 类型实例化 XmlSerializer,但您仍然可以从主程序集中为 Class2 类型实例化它。这确实意味着如果您将 Class1 移动到 ClassLibrary1 或将 Class2 移动到主程序集 - 它将反序列化而不会出错。它有效,但不可能在任何地方都使用这个解决方案,而且它在意识形态上是错误的。
使用ILMerge 将这些程序集合并为一个。但它只适用于非 wpf 的东西,而且您应该使用程序集属性管理这种情况(可能存在冲突)。
还有一个非常糟糕的主意:
-
使用 sgen.exe 生成 ClassLibrary1.XmlSerializer.dll。
也将其嵌入到主组件中。
通过反射调用其内部方法之一将其显式加载到 XmlSerializer 缓存。
虽然我现在不得不使用一号解决方案,但我并不满意,因为它太约束了。
【讨论】:
【参考方案4】:我会尝试 XmlSerializer(Type, Type[]) 构造函数并使用第二个参数提供 Class2 作为附加类型。我对 XmlSerializer 的使用经验很少,但是对于 DataContractSerializer,这可以解决问题。
【讨论】:
以上是关于反序列化具有在 AssemblyResolve 上加载的其他程序集中声明的类型字段的对象时出错的主要内容,如果未能解决你的问题,请参考以下文章
当 DisallowApplicationBaseProbing = true 时需要连接 AssemblyResolve 事件