【问题标题】:C# deserialization fails in Automation Addin but not in NUnit testsC# 反序列化在自动化插件中失败,但在 NUnit 测试中失败
【发布时间】:2011-10-14 04:45:38
【问题描述】:

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

谢谢。

【问题讨论】:

  • 更新:删除 AssemblyFormat 设置并不能解决问题。这存在的唯一原因是为了帮助单元测试(我只是加载以前的序列化数据)
  • 我很确定这是由于 [ClassInterface(ClassInterfaceType.AutoDual)] 产生警告“...使用 ClassInterface(ClassInterfaceType.AutoDual) 可能版本不正确...”代码:CA1408。所以现在我需要找到一种方法来删除这个 ClassInterface,它仍然允许自动化插件注册 UDF 并实现 IDTExtensibility2 来处理 Excel.Application

标签: c# excel serialization deserialization


【解决方案1】:

我一直在寻找红鲱鱼,但假设这是一个版本控制问题(我查看了垫片和各种各样的东西),却一无所获。

这实际上是由于奇怪的程序集绑定;尽管自动化插件的 DLL 可以从它所依赖的 DLL 中查看和加载类,但当它可以进行反序列化时,它无法找到必要的程序集——即使反序列化调用来自属于它声称无法找到的 DLL 的类找到!

解决方案当然是一个 hack,但它让我克服了这个问题,所以如果其他人像我一样被卡住,这里是 hack(s):

在类 X 中,它依赖于各自项目 DLL 中的类 Y 和 Z(名为 ProjectForX、ProjectForY 和 ProjectForZ)

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;
        }
    }

基本上它只是挂钩到解析事件并根据请求的类型名称提供正确的程序集 - 这不是特别安全(我在程序集描述符中使用逗号来尽量减少任何冲突)。

几乎可以肯定有一种明确的方法可以做到这一点,而问题可能只是配置不佳以及我对 MS 产品和 C# 的有限经验造成的。

如果我只是构建一个单一的 DLL,这不会是一个问题 =)

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2018-04-11
    • 2012-03-25
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多