c# - 关于如何使用类似插件的体系结构实现 c# 主机应用程序的问题

标签 c# .net multithreading plugins appdomain

我想要一个应用程序作为许多其他小应用程序的主机。这些应用程序中的每一个都应该作为这个主应用程序的插件。我之所以称它们为插件,并不是因为它们向主应用程序添加了一些东西,而是因为它们只能与这个主机应用程序一起工作,因为它们依赖于它的某些服务。

我的想法是让每个插件都在不同的应用域中运行。问题似乎是我的主机应用程序应该有一组我的插件想要使用的服务,据我所知,让数据流入和流出不同的应用程序域并不是一件好事。

一方面,我希望它们表现为独立的应用程序(尽管,正如我所说,它们需要多次使用主机应用程序服务),但另一方面,如果有的话,我也希望如此它们中的一部分崩溃了,我的主应用程序不会受到影响。

对于这种情况,最好的 (.NET) 方法是什么?让它们都在同一个 AppDomain 上运行,但每个都在不同的线程中运行?使用不同的 AppDomains?每个“插件”一个?我如何让他们与主机应用程序通信?还有其他方法吗?

虽然速度在这里不是问题,但我不希望函数调用比我们仅使用常规 .NET 应用程序时慢得多。

谢谢

编辑:也许我真的需要使用不同的 AppDomain。根据我的阅读,在不同的 AppDomain 中加载程序集是以后能够从进程中卸载它们的唯一方法。

最佳答案

我已经使用 System.Addin 命名空间中的托管插件框架 (MAF) 沿这些思路实现了一些东西。使用 MAF,您可以将插件打包为单独的 DLL,您的主机应用程序可以在其应用程序域、所有插件的单独域中或每个插件在其自己的域中发现并启动这些 DLL。使用卷影副本和单独的域,您甚至可以在不关闭主机应用程序的情况下更新插件。

您的主机应用程序和插件通过您从 MAF 接口(interface)派生的契约(Contract)进行通信。您可以在主机和插件之间来回发送对象。协议(protocol)在插件和主机之间提供了一个黑盒接口(interface),允许您在主机不知道的情况下更改插件的实现。

如果宿主告诉它们彼此,插件甚至可以相互通信。在我的例子中,一个日志插件由其他人共享。这让我可以在不接触其他插件或主机的情况下放入不同的记录器。

对于我的应用程序,插件使用简单的主管类,它们在自己的线程上启动工作类,完成所有处理。 worker 捕获他们自己的异常,他们通过回调方法返回给他们的主管。主管可以重新启动 worker 或采取其他行动。宿主机通过命令合约控制监管者,指示他们启动和停止 worker 并返回数据。

我的主机应用程序是 Windows 服务。工作线程因所有常见原因(包括错误!)而抛出异常,但主机应用程序从未在我们的任何安装中崩溃。由于调试服务不方便,插件允许我构建使用相同合约的测试应用程序,并进一步保证我正在测试我部署的内容。

插件也可以公开 UI 元素。这对我非常有帮助,因为我需要使用主机服务部署 Controller 应用程序,因为服务没有 UI。每个插件都包含自己的 Controller 接口(interface)。 Controller 应用程序本身非常简单——它加载插件并显示它们的 UI 元素。这使我可以发布具有更新界面的更新插件,而不必发布新 Controller 。

即使 Controller 和主机服务使用相同的插件,它们也不会互相踩踏;事实上,他们甚至不知道另一个应用程序正在使用相同的插件。 Controller 和主机通过共享数据库相互通信,但您也可以使用其他应用程序间机制,如 MSMQ。在下一个版本中,主机将是一个 WCF 服务,在后端和 Web 服务上有插件用于控制。

这有点啰嗦,但我想让您了解 MAF 的用途。它并不像乍看起来那么复杂,您可以使用它构建坚如磐石的应用程序。

关于c# - 关于如何使用类似插件的体系结构实现 c# 主机应用程序的问题,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/2695468/

相关文章:

c# - C# 中的 C++ 非托管 DLL

c# - 我如何在 C# 中访问硬盘驱动器中的所有分区

c# - 将 Xml 代码段作为参数传递到 xslt

c# - EF Core 多个 HTTP 请求抛出错误

c# - 将 OPC UA 服务器添加到 .NET 应用程序

从同步块(synchronized block)调用 wait 时出现 java.lang.IllegalMonitorStateException

c# - (对象)0 ==(对象)0

c# - 批量插入时如何自动截断字符串?

java - Hibernate拦截器线程安全

c++ - 为什么这段代码中调用了两次析构函数?