BinaryFormatter Deserialisation在通过COM interop使用时抛出异常

问题描述:

我必须更新一些旧应用程序(vb6),并且我一直使用COM interop在c#(Visual Studio 2010)中编写新代码。它的大部分工作正常,但我遇到了一个问题,我不知道是什么导致它。BinaryFormatter Deserialisation在通过COM interop使用时抛出异常

我用下面的方法来出于某种原因执行对象

public static T CloneObject<T>(T source) 
    { 
     T destination = default(T); 

     if (!typeof(T).IsSerializable) 
     { 
      throw new ArgumentException("The type must be serialisable.", "source"); 
     } 

     if (Object.ReferenceEquals(source, null)) 
     { 
      return default(T); 
     } 

     using (Stream ms = new MemoryStream()) 
     { 
      BinaryFormatter formatter = new BinaryFormatter(); 
      formatter.Serialize(ms, source); 
      ms.Position = 0; 

      destination = (T)formatter.Deserialize(ms); 
     } 

     return destination; 
    } 

的深层副本误码出来的时候,反序列化函数被调用。它引发的异常是找不到代码所在的程序集。

无法找到程序集“AssemblyBeingUsed,版本= 1.0.0.0,文化=中立,公钥=空”

这是稍微有一些混乱我为集已被访问及其说它无法找到。格式化错误消息的代码是同一个程序集的一部分!

以下是异常的堆栈跟踪。

在System.Runtime.Serialization.Formatters.Binary.BinaryAssemblyInfo.GetAssembly() 在System.Runtime.Serialization.Formatters.Binary.ObjectReader.GetType(BinaryAssemblyInfo集信息,字符串名称) 在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) 在System.Runtime.Serialization.Formatters.Binary.BinaryFormatter.Deserialize(流serializationStream,HeaderHandler处理器,布尔FCHECK,布尔isCrossAppDomain,IMethodCallMessage methodCallMessage)

编辑:更多有用的信息。

此功能从不直接从vb6调用。因为它使用泛型,我敢肯定,这是不可能的。该函数是从vb6应用程序加载的表单中调用的。当从c#应用程序使用这个表单时,即使它执行完全相同的操作也没有问题。

Visual Studio项目使用“Register for COM interop”选项,程序集作为参考加载到vb6项目中。

编辑:从fuslogvw.exe

输出的输出从fuslogvw.exe示出了具有我感兴趣的(BarcodeAndOperatorDatabase)的组件相关联5名的条目。由于它们合并时间相当长,我已将所有输出上传到 this file

说实话,我不知道我在看什么。有3个操作,我认为当程序集绑定发生时对应于:

15:29:06:VB6应用程序启动,操作成功。 (2条目):从程序集加载的表单(我认为),操作失败。这是令人困惑的表单加载正确,并可以交互。

15:29:50(2个条目):当调用CloneObject方法时操作失败的按钮单击失败。

+0

一个狂野的镜头,但你有多个目录中的dll?如果你有这样的暮光区行为时,可以发现exe的2个相同的DLL副本。 –

+0

它看起来像解析一个整数有问题。输入是否有空值?尝试int?而不是int。整数是否有小数位(句点或逗号)? +/-和数字之间有空格吗? VB在处理不同的数字格式方面稍微好一些。 – jdweng

+0

显然不使用GAC,我闻到Assembly.LoadFile()鼠。 –

TLDR版本:

系统找不到组件。解决方案是为事件添加处理程序,并返回对所需程序集的引用。

长的版本:

堆栈跟踪与System.Runtime.Serialization.Formatters.Binary.BinaryAssemblyInfo.GetAssembly()完成。如果你沿源代码中的方法调用进一步向下,你会看到下面的代码被调用。

internal static Assembly LoadAssemblyFromString(String assemblyName) { 
     // 
     // Try using the stringized assembly name to load from the fusion cache. 
     // 
     BCLDebug.Trace("SER", "[LoadAssemblyFromString]Looking for assembly: ", assemblyName); 
     Assembly found = Assembly.Load(assemblyName); 
     return found; 
    } 

这一呼吁的融合日志:

*** Assembly Binder Log Entry (14/06/2017 @ 15:29:50) *** 

The operation failed. 
Bind result: hr = 0x80070002. The system cannot find the file specified. 

Assembly manager loaded from: C:\Windows\Microsoft.NET\Framework\v4.0.30319\clr.dll 
Running under executable C:\Program Files (x86)\Microsoft Visual Studio\VB98\vb6.exe 
--- A detailed error log follows. 

=== Pre-bind state information === 
LOG: DisplayName = BarcodeAndOperatorDatabase, Version=1.0.4.0, Culture=neutral, PublicKeyToken=null 
(Fully-specified) 
LOG: Appbase = file:///C:/Program Files (x86)/Microsoft Visual Studio/VB98/ 
LOG: Initial PrivatePath = NULL 
LOG: Dynamic Base = NULL 
LOG: Cache Base = NULL 
LOG: AppName = vb6.exe 
Calling assembly : (Unknown). 
=== 
LOG: This bind starts in default load context. 
LOG: No application configuration file found. 
LOG: Using host configuration file: 
LOG: Using machine configuration file from C:\Windows\Microsoft.NET\Framework\v4.0.30319\config\machine.config. 
LOG: Policy not being applied to reference at this time (private, custom, partial, or location-based assembly bind). 
LOG: The same bind was seen before, and was failed with hr = 0x80070002. 
ERR: Unrecoverable error occurred during pre-download check (hr = 0x80070002). 

的问题是,该系统的探测下“Appbase`(C列出的目录:\程序文件(x86)\微软的Visual Studio \ VB98),因为所需的程序集不在该目录下,所以找不到它。

在COM加载CLR和CLR加载程序集时,它基于存储在注册表中的路径。这可以从这个日志条目中看到。

=== Pre-bind state information === 
LOG: Where-ref bind. Location = D:/Development/Library/C Sharp/BarcodeAndOperatorDatabase/BarcodeAndOperatorDatabase/bin/x86/ComInterop/BarcodeAndOperatorDatabase.dll 
LOG: Appbase = file:///C:/Program Files (x86)/Microsoft Visual Studio/VB98/ 
LOG: Initial PrivatePath = NULL 
LOG: Dynamic Base = NULL 
LOG: Cache Base = NULL 
LOG: AppName = vb6.exe 
Calling assembly : (Unknown). 
=== 
LOG: This bind starts in LoadFrom load context. 
WRN: Native image will not be probed in LoadFrom context. Native image will only be probed in default load context, like with Assembly.Load(). 
LOG: No application configuration file found. 
LOG: Using host configuration file: 
LOG: Using machine configuration file from C:\Windows\Microsoft.NET\Framework\v4.0.30319\config\machine.config. 
LOG: Attempting download of new URL file:///D:/Development/Library/C Sharp/BarcodeAndOperatorDatabase/BarcodeAndOperatorDatabase/bin/x86/ComInterop/BarcodeAndOperatorDatabase.dll. 
LOG: Assembly download was successful. Attempting setup of file: D:\Development\Library\C Sharp\BarcodeAndOperatorDatabase\BarcodeAndOperatorDatabase\bin\x86\ComInterop\BarcodeAndOperatorDatabase.dll 
LOG: Entering run-from-source setup phase. 
LOG: Assembly Name is: BarcodeAndOperatorDatabase, Version=1.0.4.0, Culture=neutral, PublicKeyToken=null 
LOG: Re-apply policy for where-ref bind. 
LOG: Where-ref bind Codebase does not match what is found in default context. Keep the result in LoadFrom context. 
LOG: Binding succeeds. Returns assembly from D:\Development\Library\C Sharp\BarcodeAndOperatorDatabase\BarcodeAndOperatorDatabase\bin\x86\ComInterop\BarcodeAndOperatorDatabase.dll. 
LOG: Assembly is loaded in LoadFrom load context. 

最初组件只存在于LoadFrom load context和探测default load context当不能找到。因此,在探测default load context时,需要提供一种方法来通过LoadFrom组件。这可以通过处理AppDomain.AssemblyResolve事件来完成。

以下摘录自:Best Practices for Assembly Loading提供了各种背景的描述。

内的应用领域,组件可被装载到 之一三个上下文,或者它们可以在没有上下文被加载:

默认负载上下文包含通过探测 全局程序集缓存发现组件,所述主机程序集存储(如果运行时为 )(例如,在SQL Server中)以及ApplicationBase和 应用程序域的PrivateBinPath。 Load的大部分重载方法都会将程序集加载到此上下文中。

来自上下文的负载包含从加载程序未搜索的 位置加载的程序集。例如,加载项 可能安装在不在应用程序 路径下的目录中。 System.Reflection.Assembly.LoadFrom, System.AppDomain。CreateInstanceFrom和 System.AppDomain.ExecuteAssembly是通过 路径加载的方法示例。

仅反射上下文包含使用ReflectionOnlyLoad和ReflectionOnlyLoadFrom方法加载的程序集。此 上下文中的代码无法执行,因此不在此讨论。有关更多 信息,请参阅如何:将组件加载到仅反射 上下文中。