在程序启动后复制DLL时,在运行时加载程序集失败

在运行时我加载一个程序集

Assembly assembly = Assembly.LoadFrom(@"c:\MyFolder\MyAssembly.dll"); 

如果程序集位于该文件夹中,则此方法有效。

如果程序集不在文件夹中,我会得到一个例外,当然告诉我无法找到程序集或其中一个依赖项。

我正在捕获exception并向用户显示错误消息。 该程序继续运行。

如果我现在将缺少的程序集复制到文件夹“c:\ MyFolder”,同时程序仍在运行并再次触发执行上述行的函数, 我得到相同的exception – 一个System.IO.FileNotFoundException – 再次表示程序集可以虽然DLL现在在文件夹中,但是找不到

如果我重新启动应用程序它可以工作,并找到程序集。 如果我在应用程序启动后第一次尝试加载程序集之前启动应用程序并将DLL复制到该文件夹​​,它也可以工作。

所以问题似乎与Assembly.LoadFrom的第一次失败调用有关。

这种行为可能是什么原因,我该怎么做才能解决问题?

提前谢谢你的帮助!

编辑:还有一个细节:

我添加了一个File.Exists测试:

 string filename = @"c:\MyFolder\MyAssembly.dll"; bool test = File.Exists(filename); Assembly assembly = Assembly.LoadFrom(filename); 

test返回trueAssembly.LoadFrom抛出FileNotFoundException

function,而不是错误。 这是一个DLL地狱反措施。 操作术语是“加载上下文”,在Suzanne Cook的博客中搜索关于它的更多信息。 简而言之,CLR记忆了以前加载程序集的尝试。 首先,它记录成功的绑定并保证即使磁盘内容已更改,也会再次加载完全相同的程序集。 你无疑可以看到它的好处,突然得到另一个组装几乎总是灾难性的。

失败的assembly绑定也是如此。 它也会记住这些,出于同样的原因,它将来会失败。 没有记录的方法来重置我所知道的加载上下文。 Assembly.LoadFile()加载没有加载上下文的程序集。 但这会导致一系列其他问题,你真的不想使用它。

为了绕过LoadFrom尝试的CLR缓存,您可以稍微更改代码以使用Assembly.Load(byte[] rawAssembly)重载。

像这样的东西:

 Assembly LoadWithoutCache(string path) { using (var fs = new FileStream(path, FileMode.Open)) { var rawAssembly = new byte[fs.Length]; fs.Read(rawAssembly, 0, rawAssembly.Length); return Assembly.Load(rawAssembly); } }