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

Posted

技术标签:

【中文标题】.net 自动装配解决加载重复装配【英文标题】:.net automatic assembly resolve loads duplicate assembly 【发布时间】:2017-02-28 18:16:01 【问题描述】:

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

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

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

而不是这个:

Assembly.LoadFrom(assemblyFile.FullName);

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

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

示例日志输出:

加载库 X 初始化库 X 加载可执行文件 Y 正在加载库 X

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

【问题讨论】:

两个负载是否发生在同一个 AppDomain 中? @DanField 是的,我仔细检查了 【参考方案1】:

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

请注意,此方法重载始终会创建一个具有自己映射的新 Assembly 对象。

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

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

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

【讨论】:

【参考方案2】:

我最终修改了沙盒的 AppDomainSetup:

domainSetup.DisallowApplicationBaseProbing = true;

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

【讨论】:

以上是关于.net 自动装配解决加载重复装配的主要内容,如果未能解决你的问题,请参考以下文章

Spring Boot 自动装配定义与自定义starter原理,及如何实现自定义装配

Spring Boot 自动装配定义与自定义starter原理,及如何实现自定义装配

Spring boot 自动装配

Spring boot 自动装配

解决自定义Shiro.Realm扩展类不能用注解(@Resource或@Autowire)自动装配的问题

Spring自动装配空指针异常[重复]