C#反序列化在Automation Addin中失败,但在NUnit测试中失败

时间:2011-07-27 11:44:40

标签: c# excel serialization deserialization

我有一个用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中进行反序列化?)

感谢。

1 个答案:

答案 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 =)

,这不会是一个问题