防止在工作目录中加载 dll,InvalidCastException Type A 无法转换为 Type B

Posted

技术标签:

【中文标题】防止在工作目录中加载 dll,InvalidCastException Type A 无法转换为 Type B【英文标题】:Preventing loading dll in working directory, InvalidCastException Type A cannot be cast to Type B 【发布时间】:2012-09-19 19:21:35 【问题描述】:

是否可以阻止加载工作目录中的 dll 并强制它在我指定的其他地方使用 dll?

我正在尝试运行一些单元测试并收到此 InvalidCast 异常:

[A]AssemblyA.DataType 不能转换为 [B]AssemblyA.DataType。 A型 源自'AssemblyA,版本=1.0.4645.21698,文化=中性, PublicKeyToken=null' 在上下文 'LoadFrom' 的位置 'E:\webservice\bin\AssemblyA\AssemblyA.dll'。 B型起源于 'AssemblyA,版本=1.0.4645.21698,文化=中性, PublicKeyToken=null' 在上下文“默认”的位置 'E:\TestResults\Out\AssemblyA.dll'。

在测试启动时,它会调用一些初始化代码,这些代码使用 Assembly.LoadFrom 从 E:\webservice\bin\AssemblyA\AssemblyA.dll 加载 dll 并创建一些类型并将它们放入缓存中。

存在将 dll 复制到该位置的构建后事件,因此它们在两个位置都是完全相同的 dll。

但是单元测试是从 E:\testresults\out\ 的工作目录运行的,所以它会自动在那里加载 AssemblyA.dll,忽略已经加载的程序集,而没有给我机会用 Appdomain 拦截该加载.AssemblyResolve 事件

因此,当单元测试代码尝试从 E:\webservice\bin\AssemblyA\AssemblyA.dll 中的缓存中检索对象时,它会说无效转换,因为它期望来自 E:\TestResults\ 的类型输出\AssemblyA.dll

查看Best Practices for Assembly Loading 后,似乎没有办法阻止它从工作目录加载 dll,即使我已经手动加载了我想要使用的 dll。除了将应用程序更改为根本不从 E:\webservice\bin... 加载之外,还有其他选择吗?

(使用 LoadFile 或 Load byte[] 也会导致同样的错误)

【问题讨论】:

我不明白您为什么引用程序集,这不正确?顺便说一句:你不能关闭CLR的默认加载行为。 这只是系统现有的架构,它是这样设置的,以允许加载不同子文件夹中的不同版本的弱命名dll。可能有更好的方法可以实现相同的结果,但我现在仍然坚持。它以前没有任何单元测试,所以这从来不是问题。 我建议编写不同的单元测试。 test projectA 正在引用 assemblyA 并对其进行测试。另一个test projectB 正在引用和测试assemblyB。这是一个想法吗? 问题在于,AssemblyA和AssemblyB都引用了共享代码,该共享代码是从另一个位置执行dll的LoadFrom而不是使用工作目录中的dll System.AddIn 处理此问题的方式是在引用程序集上禁止 CopyLocal=true。这种方式仅通过调用 LoadFrom 而不是由 CLR 程序集加载器加载。 【参考方案1】:

现在,我想帮你解决问题..

我建议使用StrongName 签署您的程序集。

CLR 使用它来识别程序集。这几乎不能解决你的问题。 但是为了解决您的问题,我建议使用接口来封装您的不同类型。因此,您可以将任何类型存储在缓存中并仅返回接口,然后演员表就消失了。

如果这不能解决您的问题,您必须向我提供更多信息。

【讨论】:

这是一个最终改进系统的好主意,因为现在我将重写我正在测试的代码,这样它就不会与从其他程序集加载的类型交互。所以它仍然会加载两个程序集,但它们不会交互导致 InvalidCastException【参考方案2】:

正如 Panos 在上面的评论中建议的那样,通过在引用的程序集上设置 CopyLocal=false 解决了这个问题。这样,CLR 就无法尝试从工作目录加载 dll,因为 dll 不存在。

【讨论】:

以上是关于防止在工作目录中加载 dll,InvalidCastException Type A 无法转换为 Type B的主要内容,如果未能解决你的问题,请参考以下文章

在主线程和工作线程中加载动态库(内部调用COM dll)有什么区别?

在 C/C++ (Win64) 中从内存中加载 64 位 DLL

试图从其文件夹中加载 dll 的应用程序

无法在 Vista x64 的 C# 应用程序中加载 C++ DLL

防止浏览器在 Angular 中加载拖放文件

sqljdbc_auth.dll 已在另一个类加载器中加载