防止在工作目录中加载 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