模块化应用程序架构和Castle Windsor

时间:2012-09-21 10:13:12

标签: c# dependency-injection castle-windsor

我正在开发一个与科学仪器互动的.Net桌面应用程序。这个仪器有很多变种,每个都有不同的功能,组件等,所以我想出了一个插件/模块化架构,其中“模块组件”包含所有必要的业务逻辑,UI等。与该硬件组件/功能进行交互。

目前我有一个包含所有内容的解决方案 - “核心”应用程序项目,公共库以及“模块”项目。我们的想法是将整个批次安装到客户站点(而不是挑选他们需要的DLL),并使用包含所需模块列表的配置文件“激活”相关模块。

主应用程序项目使用Castle Windsor加载模块,使用AssemblyFilter和自定义InstallerFactory。它搜索每个模块程序集,查找实现IWindsorInstaller 的类,该类使用特定的自定义属性(具有包含模块名称的属性)进行修饰。仅当属性的模块名称是请求的模块名称之一时,才会运行模块的安装程序。这些安装程序类负责使用Windsor注册该模块所需的所有内容(业务逻辑,视图,视图模型等)。

此解决方案在我的概念验证中运行良好,但是我可以看到两个或更多模块在功能上非常相似的情况,因此需要共享公共代码。假设我有项目“ModuleA”和“ModuleB”,他们的Windsor安装程序在项目“ClassLibraryX”中注册相同的IFooService类。该应用程序将因为IFooService被重新刷新两次而失败,而Windsor将不知道在构造函数请求时要解析哪一个。

处理此问题的最佳方法是什么?到目前为止的想法: -

  • 查明某个特定组件是否已在Windsor注册。这感觉很糟糕(如果可能的话)
  • 使用名称注册组件,但如何使用构造函数注入请求命名实例?
  • 在每个模块项目中创建一个新界面,例如public interface IModuleAFooService : IFooService,并在整个项目中注册/使用它(而不是IFooService)。

有什么想法吗?

修改:实际上,Windsor在尝试解析IFooService时不会挫败。当第二个模块尝试注册相同的接口/具体实现时,它将会崩溃!

3 个答案:

答案 0 :(得分:0)

你能否为插件提供一些元数据,即为每个插件实现提供一个名称属性,windsor可以使用它来识别你想要的实现?

我最近没有使用过Castle,但我确信它确实有命名Bindings / Registrations的概念,所以你可以用它来区分事物,如果那是不可能的,那就没有了您可以想到的其他元数据会使Windsor不那么模糊,那么我会选择第3个选项。

刚刚读完你的第二个选项(在写完上面的内容之后)似乎是最好的选择,我不记得EXACT语法,但在大多数DI框架中,你做的事情如下:

var instance = Get<IMyInterface>("Named This");

在他们的文档中会有大量的语法示例,但您需要知道Windsor一侧的名称才能注册它并在客户端请求它。

答案 1 :(得分:0)

我看到它的方式,你有几个选择。我认为你有两个主要问题。首先是您要安装共享接口两次(或更多)。第二个是你可以有两个不同版本的共享接口。

对于第一个问题,我将共享接口分离到它们自己的程序集中。在该程序集中,我将有一个作用于该程序集的安装程序。然后,您可以告诉Windsor安装该共享组件,它知道如何连接自己。

对于第二个问题,你有两个选择(我看到它)。第一个选项是让您的共享组件向后兼容。第二个选项是隔离运行时(通过应用程序域或进程)。

答案 2 :(得分:0)

命名实例没问题。您可以通过流畅配置中的DependsOn(Dependency.OnComponent("paramName", "serviceName"))方法定义对具体命名服务的依赖性。