.net 自动装配解决加载重复装配

.net automatic assembly resolve loads duplicate assembly

我有一个依赖库的可执行文件。我还有一个 "loader" 应用程序,它将可执行文件加载到单独的 AppDomain(我的 "sandbox")并在那里运行。该库需要从沙箱外部进行初始化,因此我需要在加载可执行文件之前加载该库。这按预期工作,但是当我现在加载可执行文件时,库会在另一次加载,并且可执行文件使用未初始化的副本。

只有当我像这样加载库时才会发生这种情况:

 Assembly.Load(File.ReadAllBytes(assemblyFile.FullName));

而不是这个:

Assembly.LoadFrom(assemblyFile.FullName);

但是,使用 LoadFrom 会锁定文件。我需要能够 delete/write 文件,因为我的应用程序需要能够重新加载整个沙箱和其中的所有程序集。

我也试过注册AppDomain.AssemblyResolve,但只有在找不到文件时才会调用,这不是我想要的...

示例日志输出:

所以我的问题是:如何强制 .net 使用已经加载的程序集而不是加载副本?

来自remarks on Assembly.Load(Byte[])

Note that this method overload always creates a new Assembly object with its own mapping.

如果您想重用已加载的程序集,则不能使用该重载(无论如何都不需要额外的工作 - 框架不会在此处自动为您完成)。

您可以在这里使用 Assembly.Load(string) 或仅使用 Type.GetType(string) 方法,但我怀疑这仍然会导致锁定您要修改的文件。老实说,我不太确定如何在 运行 时间修改这些文件 - 如果删除或更改加载的程序集,预期的行为是什么?重新加载它?修改后的代码是否进入内存?

您可能需要创建自己的某种程序集缓存机制。如果程序集不是那么大并且您可以负担得起将它们保存在内存中,那么它可能像 Dictionary<string, Assembly> 一样简单 - 只需在加载之前检查字典是否包含您的程序集,否则使用 Assembly.Load(Byte[])你现在的样子。

我最终修改了沙盒的 AppDomainSetup:

domainSetup.DisallowApplicationBaseProbing = true;

现在,每次都会调用 AssemblyResolve(不会自动发现程序集)。现在我可以从 byte[] 加载程序集并缓存它们(感谢建议缓存程序集的@DanField)