.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原理,及如何实现自定义装配