.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,但只有在找不到文件时才会调用,这不是我想要的...
示例日志输出:
- 正在加载库 X <- 手动加载
- 正在初始化库 X
- 正在加载可执行文件 Y
- 正在加载库 X <- 不好,我想使用加载的 X!
所以我的问题是:如何强制 .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)
我有一个依赖库的可执行文件。我还有一个 "loader" 应用程序,它将可执行文件加载到单独的 AppDomain(我的 "sandbox")并在那里运行。该库需要从沙箱外部进行初始化,因此我需要在加载可执行文件之前加载该库。这按预期工作,但是当我现在加载可执行文件时,库会在另一次加载,并且可执行文件使用未初始化的副本。
只有当我像这样加载库时才会发生这种情况:
Assembly.Load(File.ReadAllBytes(assemblyFile.FullName));
而不是这个:
Assembly.LoadFrom(assemblyFile.FullName);
但是,使用 LoadFrom 会锁定文件。我需要能够 delete/write 文件,因为我的应用程序需要能够重新加载整个沙箱和其中的所有程序集。
我也试过注册AppDomain.AssemblyResolve,但只有在找不到文件时才会调用,这不是我想要的...
示例日志输出:
- 正在加载库 X <- 手动加载
- 正在初始化库 X
- 正在加载可执行文件 Y
- 正在加载库 X <- 不好,我想使用加载的 X!
所以我的问题是:如何强制 .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)