Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/265.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 模块化应用程序体系结构和Castle Windsor_C#_Dependency Injection_Castle Windsor - Fatal编程技术网

C# 模块化应用程序体系结构和Castle Windsor

C# 模块化应用程序体系结构和Castle Windsor,c#,dependency-injection,castle-windsor,C#,Dependency Injection,Castle Windsor,我正在开发一个与科学仪器交互的.Net桌面应用程序。该工具有许多变体,每个变体都有不同的功能、组件等,因此我提出了一个插件/模块化体系结构,其中“模块组件”包含所有必要的业务逻辑、UI等,以与该硬件组件/功能交互 目前,我有一个包含所有内容的解决方案——“核心”应用程序项目、公共库以及“模块”项目。我们的想法是将全部安装到客户站点(而不是挑选他们需要的DLL),并使用包含所需模块列表的配置文件“激活”相关模块 主应用程序项目使用Castle Windsor、AssemblyFilter和自定义I

我正在开发一个与科学仪器交互的.Net桌面应用程序。该工具有许多变体,每个变体都有不同的功能、组件等,因此我提出了一个插件/模块化体系结构,其中“模块组件”包含所有必要的业务逻辑、UI等,以与该硬件组件/功能交互

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

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

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

最好的处理方法是什么?迄今为止的想法:-

  • 了解特定组件是否已在温莎注册。这感觉很不舒服(如果可能的话)
  • 使用名称注册组件,但如何使用构造函数注入请求命名实例
  • 在每个模块项目中创建一个新接口,例如
    公共接口IModuleAFooService:IFooService
    ,并在整个项目中注册/使用该接口(而不是
    IFooService
有什么想法吗


编辑:事实上,Windsor在尝试解决
iFoosService
问题时不会失败。当第二个模块尝试注册相同的接口/具体实现时,它将失效

您能否为插件提供一些元数据,即为每个插件实现提供一个名称属性,windsor可以使用该属性确定您想要的实现

我最近没有太多地使用Castle,但我确信它确实有命名绑定/注册的概念,因此您可以使用它作为区分事物的一种方式,如果这是不可能的,并且没有其他元数据可以让Windsor不那么模棱两可,那么我会选择你的第三个选择

刚刚再次阅读了您的第二个选项(在写了上面的内容之后),这似乎是最好的选项,我记不起确切的语法,但在大多数DI框架中,您会执行以下操作:

var instance = Get<IMyInterface>("Named This");
var instance=Get(“命名此”);

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

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

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


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

命名实例可以。您可以通过fluent配置中的
DependsOn(dependency.OnComponent(“paramName”、“serviceName”))
方法定义对具体命名服务的依赖关系。

我还考虑在“共享”程序集中安装一个安装程序,但我想这意味着注册这些共享组件,而不管是否有任何依赖模块被“激活”。也许我只是在小题大做,不必要的注册(发生在启动时)开销最小。是的,我认为可用组件的注册开销很小。我会这样想:您正在激活可以使用的核心组件,但每个模块都会在执行之前确保其处于活动状态。问题是我的应用程序可能会加载两个插件,这两个插件都需要相同的实现。每个插件都负责向Windsor注册其依赖项,并且不知道其他插件是否已经注册了相同的实现,导致相同的实现被注册两次,从而导致Windsor崩溃。我知道你可以用不同的名字注册同一个实现,但我不确定在使用构造函数注入时你如何告诉Windsor你想要哪一个。哦,我同意你的看法,如果是这样的话,你似乎忽略了一个问题。如果您有两个插件,它们都具有所需接口的实现,比如说
ZipPlugin
RarPlugin
,它们都共享一个您需要的实现,名为
CompressedFile:ICompressedFile
,您可能没有该实现的相同版本