2012-09-21 51 views
0

我正在开发与科学仪器交互的.Net桌面应用程序。这个工具有很多种不同的形式,每种都有不同的特性,组件等,所以我想出了一个插件/模块化架构,其中“模块组件”包含所有必要的业务逻辑,用户界面等与该硬件组件/功能进行交互。模块化应用程序体系结构和Castle Windsor

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

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

该解决方案在我的概念证明中工作正常,但是我可以看到两个或更多个模块在功能上非常相似的情况,因此需要共享通用代码。假设我有项目“ModuleA”和“ModuleB”,他们的Windsor安装人员在项目“ClassLibraryX”中注册了相同的IFooService类。该应用程序将会崩溃,因为IFooService已被重新编写了两次,而Windsor在构造函数请求时不会知道要解析哪一个。

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

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

有什么想法?

编辑:事实上,当Windsor尝试分辨IFooService时,它不会倒下。当第二个模块尝试注册相同的接口/具体实现时,它会崩溃!

回答

0

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

对于第一个问题,我会将共享接口分离出它们自己的程序集。在该程序集内部,我将有一个安装程序,该安装程序的范围是该程序集。然后,您可以告诉Windsor安装该共享组件,并知道如何连线。

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

+0

我也想过在“共享”程序集中安装一个安装程序,但我想这意味着要注册这些共享组件,而不管是否有任何相关模块已被“激活”。也许我只是从一座痣山上爬出一座山,而不必要的注册(这在启动时发生)的开销很小。 –

+1

是的,我认为可用组件的注册几乎没有开销。我会这样想:您正在激活可以使用的核心组件,但是每个模块都会在执行之前确保它处于活动状态。 –

0

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

最近我还没有使用过多的Castle,但我确信它确实有命名绑定/注册的概念,所以您可以使用它作为区分事物的一种方式,如果这不可行并且存在没有其他的元数据可以使用,这会让Windsor不那么模糊,那么我会选择第三个选项。

刚刚看了一遍你的第二个选项(写了上之后),这似乎是最好的选择,我不记得确切的语法,但在大多数投资框架,你做这样的事情:

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

会有负载但是您需要知道Windsor端的名称,并在客户端注册并请求它。

+0

问题是我的应用程序可能会加载两个插件,都需要相同的实现。每个插件是负责与温莎注册其依赖关系,并会不知道另外一个插件已经注册了相同的执行,导致执行同样被注册两次,导致温莎摔倒。我知道你可以用不同的名字注册相同的实现,但是当我使用构造函数注入时,我不知道你如何告诉Windsor你想要哪一个。 –

+0

OH我和你在一起,似乎有一个问题你忽略了,如果是这样的话。如果你有2个插件都可以实现你需要的接口,可以说'ZipPlugin'和'RarPlugin',它们都共享一个你需要的实现,名为CompressedFile:ICompressedFile,你可能没有那个实现的版本,如果一个插件是版本1.0,另一个插件是2.1,那么您可能会在其中一个可能兼容或不兼容的插件中使用更新版本,因此每个插件及其共享类的版本是您可能需要考虑的。 – Grofit

0

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