我有一个用C#4编写的自动化插件(实现Extensibility.IDTExtensibility2),我正在尝试加载一些(二进制)序列化数据。它在单元测试中完美运行,但在Excel中运行时失败:
Unable to find assembly 'XXX, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null'.
at System.Runtime.Serialization.Formatters.Binary.BinaryAssemblyInfo.GetAssembly()
at System.Runtime.Serialization.Formatters.Binary.ObjectReader.GetType(BinaryAssemblyInfo assemblyInfo, String name)
at System.Runtime.Serialization.Formatters.Binary.ObjectMap..ctor(String objectName, String[] memberNames, BinaryTypeEnum[] binaryTypeEnumA, Object[] typeInformationA, Int32[] memberAssemIds, ObjectReader objectReader, Int32 objectId, BinaryAssemblyInfo assemblyInfo, SizedArray assemIdToAssemblyTable)
at System.Runtime.Serialization.Formatters.Binary.__BinaryParser.ReadObjectWithMapTyped(BinaryObjectWithMapTyped record)
at System.Runtime.Serialization.Formatters.Binary.__BinaryParser.ReadObjectWithMapTyped(BinaryHeaderEnum binaryHeaderEnum)
at System.Runtime.Serialization.Formatters.Binary.__BinaryParser.Run()
at System.Runtime.Serialization.Formatters.Binary.ObjectReader.Deserialize(HeaderHandler handler, __BinaryParser serParser, Boolean fCheck, Boolean isCrossAppDomain, IMethodCallMessage methodCallMessage)
at System.Runtime.Serialization.Formatters.Binary.BinaryFormatter.Deserialize(Stream serializationStream, HeaderHandler handler, Boolean fCheck, Boolean isCrossAppDomain, IMethodCallMessage methodCallMessage)
at System.Runtime.Serialization.Formatters.Binary.BinaryFormatter.Deserialize(Stream serializationStream)
at
在BinaryFormatter上我设置了AssemblyFormat(用于序列化和反序列化),如下所示:
serializationCodec.AssemblyFormat = System.Runtime.Serialization.Formatters.FormatterAssemblyStyle.Simple;
我认为根据here会忽略该版本。
然后认为这可能是由于Excel的“可信位置”概念所以我添加了项目的目录并检查了所有子目录,但错误仍然存在。
徒劳无功,我尝试添加System.Runtime.Serialization.OptionalFieldAttribute属性,但没有帮助。
单元测试可以加载自己生成的序列化文件或在Excel中执行的相同代码,但无论是否进行实际序列化,Excel都无法加载序列化数据。
Excel无法反序列化它自身序列化的事实暗示这是一个更加繁琐的事实,因为它显然可以访问所使用的程序集。
所以问题是为什么与我的单元测试相比,Excel反序列化的方式不同? (或者更重要的是,如何在Excel中进行反序列化?)
感谢。
答案 0 :(得分:0)
我追逐红鲱鱼并没有假设这是一个版本问题(我看过垫片和所有种类)。
实际上是由于奇怪的装配绑定;虽然自动化插件的DLL可以从它所依赖的DLL中查看和加载类,但是当它可以反序列化时它无法找到必要的程序集 - 即使反序列化调用来自属于它声称它不能的DLL的类发现!
解决方案肯定是一个黑客攻击,但它已经让我超越了这个,所以万一其他人就像我一样被卡住了,这就是黑客攻击:
在类X中,它依赖于各自项目DLL(名为ProjectForX,ProjectForY和ProjectForZ)的类Y和Z
private static Assembly MyResolveEventHandler(object sender, ResolveEventArgs args)
{
if(args.Name.StartsWith("ProjectForX,")) {
return typeof(X).Assembly;
} else if(args.Name.StartsWith("ProjectForY,")) {
return typeof(Y).Assembly;
} else if(args.Name.StartsWith("ProjectForZ,")) {
return typeof(Z).Assembly;
}
return null;
}
public static X LoadX(string filename)
{
AppDomain currentDomain = AppDomain.CurrentDomain;
ResolveEventHandler handler = new ResolveEventHandler(MyResolveEventHandler);
currentDomain.AssemblyResolve += handler;
try {
Stream stream = new FileStream(@filename, FileMode.Open);
try {
BinaryFormatter deserializer = createBinaryFormatter();
X model = (X)deserializer.Deserialize(stream);
return model;
} finally {
stream.Close();
}
} finally {
currentDomain.AssemblyResolve -= handler;
}
}
基本上它只是挂钩到resolve事件并根据请求的类型名称提供正确的程序集 - 这不是特别安全(我在程序集描述符中使用逗号来尝试最小化任何冲突)。
几乎可以肯定有一种明确的方法可以做到这一点,问题可能只是由于配置不当以及我对MS产品和C#的经验有限。
如果我刚刚构建了一个单片DLL =)
,这不会是一个问题