AppDomain 隔离问题
Posted
技术标签:
【中文标题】AppDomain 隔离问题【英文标题】:AppDomain isolation issue 【发布时间】:2012-05-21 18:13:33 【问题描述】:我以这样一种方式构建了一个后端,将业务逻辑放置在运行时加载的 dll 中。使用 ShadowCopyFiles = true 和文件系统监控,我可以在不重新启动主机进程的情况下修改业务逻辑。
到目前为止一切都很好......
让我们称主机 appdomain A,和其中一个孩子 B。
不幸的是,如果我在程序集 C 中进行更改,该程序集由 B 而不是 A 引用,这些更改不会在 B 重新加载时反映出来。我认为这是因为 A 加载 C 本身。我必须采取哪些步骤来防止 A 加载 C?
这是A用来加载B的代码:
AppDomainSetup appDomainSetup = new AppDomainSetup();
appDomainSetup.CachePath = ServiceDLLPath + @"\Shadow";
appDomainSetup.ShadowCopyFiles = "true";
ad = AppDomain.CreateDomain(assemblyName, null, appDomainSetup);
ad.InitializeLifetimeService();
try
service = (IService)ad.CreateInstanceFromAndUnwrap(assemblyName,
"AppName.Services." + typeName);
service.Start();
catch (Exception e)
LogManager.Log("AppDomain load failed: " + e.Message);
return false;
【问题讨论】:
【参考方案1】:如果A
引用C
并且A
是“主机”,则在不停止并重新启动进程的情况下无法重新加载C
。
一种可能性是制作一个非常薄的 shim AppDomain 来引导 A
AppDomain(并可以重新启动它),但重新启动该过程可能具有相同的性能配置文件。
另一种(看起来更明智)的方法是使A
和它的依赖项独立于C
使用的那些依赖项,并且对于重叠的程序集,只需使它们足够稳定,您就不需要经常更改它们.
【讨论】:
感谢您的回复,克里斯。 A 没有明确引用 C。但是 A 引用了 B,而 B 又引用了 C。那应该没问题,不是吗? 当我构建 A 时,我可以看到它创建了 C 的本地副本,尽管它没有被直接引用,所以我猜想存在某种对程序集的递归搜索。 引用是隐式递归的,是的。如果A
引用B
,而B
引用C
,则加载A
将加载C
。
这让我们回到了问题上。如何在不重启 A 的情况下更改 C?
你看我的回答了吗?除了卸载整个 appdomain 并开始一个新的 appdomain 之外,不可能更改已加载的程序集或重新加载单个程序集。您需要弄清楚如何构建您的应用程序,这样您就不需要经常更改C
,或者A
不会(直接或间接)引用它。【参考方案2】:
阅读答案和 cmets,听起来您最好将业务逻辑包装到 WCF 服务中。您可以使用网络管道来最小化在同一台电脑上运行的开销。您还应该查看 MEF 以构建应用程序可扩展性。不幸的是,MEF 也不允许您在不重新启动主机应用程序的情况下即时卸载和替换插件
【讨论】:
如果我再做一次,我会走那条路。似乎使用 Appdomains 动态加载逻辑不值得麻烦。我什至不确定在什么情况下这种 appdomain 方法优于“每个服务一个进程 + WCF”。【参考方案3】:好的,我通过创建一个“接口”程序集解决了这个问题。
所以如果这个程序集被称为 X,那么链现在是:
A -> X C
(原:A -> B -> C)
我现在可以在 B 或 C 中进行更改,这会在 appDomain B 被 A 销毁并重新启动时反映出来。
编辑,应 Tim 的要求,提供更多细节。
appdomain A 中的代码没有改变,你可以看到我的问题。唯一需要注意的是 IService 类型定义的位置:
service = (IService)ad.CreateInstanceFromAndUnwrap(assemblyName,
"AppName.Services." + typeName);
一旦将 IService 移至专门构建的程序集,我就能够删除 B 和 A 中的引用,这些引用最终以某种方式将 A 连接到 C。基本上 Chris 所说的一切都是正确的,只是并不总是清楚什么路径是。
【讨论】:
愿意向我们展示一下您是如何做到的吗?至少您的帖子将成为一个有价值的答案,并且可能还会因此获得积分。 :-) 关于更改的代码不多,请参阅我更新的答案。如果您有兴趣,我可以分享监控/重启代码。很可能会接受克里斯的回答。以上是关于AppDomain 隔离问题的主要内容,如果未能解决你的问题,请参考以下文章
将隔离的 dll 加载到现有的 Appdomain 并自动执行事件