为什么重命名 dll 扩展名(即重命名为 dllold)会在运行时导致 FileNotFound 异常?

Why does renaming a dll extension (I.e. to dllold) cause a FileNotFound exception at runtime?

似乎在某个时候,在我们其中一个网站上工作的开发人员必须手动更新生产 dll,我们称之为 "MyLibrary.dll"。为此,他们将旧的 dll 文件扩展名更改为 "dllold"。加载此站点后,我们收到 System.IO.FileNotFoundException 错误,即 Could not load file or assembly 'MyLibrary.dllold' or one of its dependencies. The system cannot find the file specified. 即使 "MyLibrary.dll" 和 "MyLibrary.dllold" 都在正确的目录中,我们仍收到此错误。只有在删除此 "dllold" 文件或完全删除扩展名的 "dll" 部分(即 MyLibrary.old)后,我们才能加载网站。

所以我想知道为什么会这样?似乎 .NET 框架的任何部分在运行时引入 dll 时只查找 "dll" 并且不关心之后的任何事情,但这并不能解释为什么它总是获取“.dllold”库而不是工作的“.dll”库。

作为参考,我们使用的是 .NET 4.0 版和 ASP.NET 4.6 版。

当加载 ASP.Net 项目时,它将尝试加载应用程序 bin 文件夹中的所有 DLL,它通过调用名为 LoadAllAssembliesFromAppDomainBinDirectory. Internally to that method, the DLLs are retrieved using the DirectortInfo.GetFiles(string) 的内部方法来实现*.dll 的模式。这匹配 .dllold,正如文档所确认的:

When using the asterisk wildcard character in a searchPattern (for example, ".txt"), the matching behavior varies depending on the length of the specified file extension. A searchPattern with a file extension of exactly three characters returns files with an extension of three or more characters, where the first three characters match the file extension specified in the searchPattern. A searchPattern with a file extension of one, two, or more than three characters returns only files with extensions of exactly that length that match the file extension specified in the searchPattern. When using the question mark wildcard character, this method returns only files that match the specified file extension. For example, given two files in a directory, "file1.txt" and "file1.txtother", a search pattern of "file?.txt" returns only the first file, while a search pattern of "file.txt" returns both files.

在程序集加载过程的其他地方,假设文件名需要 .dll 后缀,这是一个不存在的文件,因此会抛出您看到的异常。

所以这个故事的寓意是:如果你需要停止加载 DLL,将它从你的 bin 文件夹中删除,或者如果你必须把它留在那里,给它一个无法匹配的后缀。

此外,根据对 DLL 所做的更改,如果两个副本都在 bin 文件夹中,您最终会加载两个具有相同命名空间的 DLL。这可能会导致应用程序无法正常运行的其他问题。与其他按需加载程序集的 .NET 应用程序不同,ASP.NET 在启动时加载所有 DLL。