我们公司的一个产品由许多小型 Web 应用程序和 Windows 服务(又称组件)组成,每个应用程序可能驻留在不同的计算机中。其中之一是 WebForms 项目,它充当所有其他项目的配置中心。
我们现在正在设计一个功能来公开组件的一般信息。想象一个像这样的简单界面:
public interface IStatistics
{
Statistics GetStatistics();
}
我们希望在所有组件上使用相同的接口(interface),因此它集中在一个公共(public)的共享程序集上。实现最初也将是相同的,因此它位于同一个程序集中,与接口(interface)一起。
我们的想法是在每个组件上公开一个 Wcf 服务,同时使用公共(public)程序集上的实现和接口(interface)。该实现使用环境类,根据运行位置返回不同的内容,例如本地机器时间。
我想优雅地解决的问题是如何使用相同的接口(interface)将每个组件的所有实现传递到 Webform。
我们目前使用Unity ,但我想我在使用任何其他 DI 解决方案时都会面临同样的问题。我想注入(inject)这个相同接口(interface)的 5 个实现(每个组件一个),并能够按组件区分它们(想想 Dictionary<Component, IStatistics>
,其中 Component
是 Enum
)。这是必需的,因为页面上将有一个下拉菜单来选择哪个组件的信息可见,然后页面将调用正确的实现来检索结果。
我知道我可以对所有实现使用命名注册,然后注入(inject)它们。不幸的是,这将导致我:
- 页面上有 5 个不同的参数,每个参数都指向一个组件
- 使用不同的名称在容器上注册每个实现
- 在容器上显式注册我的 Web 表单,并使用自定义 InjectionConstructor 为页面注入(inject)方法以正确的顺序指定每个已注册的接口(interface)
我知道 Unity 有一个 ResolveAll 方法,因此允许接收 IStatistics[]
或IEnumerable<IStatistics>
,但这样我就无法区分它们了。
我认为MEF通过元数据接口(interface)的概念很好地解决了这个问题。也许让 MEF 来解决这个问题?我认为这里不合适,因为我们正在谈论这些 wcf 代理,我根本看不出这将如何与 MEF 集成。
也许使用工厂是一个更好的策略,但我不知道如何在工厂上注入(inject)服务,所以问题仍然存在。
最佳答案
我想知道,你是否可以将整个事情设计得稍微不同。我认为你想做的事情有点违背国际奥委会的宗旨。如果我理解正确,您需要五个相同类型的实例,您可以以某种方式将它们与其他五个不同类型的对象相关联。 “IStatistics”是在公共(public)程序集中定义的接口(interface)。比如说Statistics
的实现位于同一个程序集中。不同类型的五个实例在它们自己的“本地”程序集中定义,这些程序集由 DI 解析,而不是直接引用。
这是一个可能更简单的想法,可以实现您所需要的,同时保持可维护性和可扩展性,特别是如果您在某些时候需要为每种组件类型提供不同的实现:
组件可以使用
DefaultStatisticsProvider
来实现 IStatisticsProvider
接口(interface)。这里不涉及DI,因为在公共(public)项目中已经可以实现。
public class DefaultStatisticsProvider : IStatisticsProvider
{
public Statistics GetStatistics()
{
var statistics = new Statistics();
// Generate statistics data
return statistics;
}
}
组件直接实现IStatisticProvider
,并将方法中继到它们在构造函数中初始化的DefaultStatisticsProvider
类型的私有(private)字段:
public class ComponentA : IStatisticsProvider
{
private readonly DefaultStatisticsProvider _statisticsProvider;
public ComponentA()
{
_statisticsProvider = new DefaultStatisticsProvider();
}
Statistics IStatisticsProvider.GetStatistics()
{
// You could change this implementation later to
// use a custom statistics provider
return _statisticsProvider.GetStatistics();
}
}
现在,您可以直接将组件注册为 IStatisticsProvider
,而不必维护某种将类型与统计提供程序实例相关联的人工查找表,因为您的类型 统计提供者,这对我来说在逻辑上也有意义。类似于(伪代码):
Container.Register<ComponentA>().As<IStatisticsProvider>();
Container.Register<ComponentB>().As<IStatisticsProvider>();
这样
Container.ResolveAll<IStatisticsProvider>();
会给你
{ Instance of ComponentA, Instance of ComponentB }
此外,如前所述,如果您在某些时候需要自定义实现来提供统计信息,则根本不需要重新设计。您只需更改组件中 GetStatistics()
的实现即可。
关于.net - 使用 DI 传递同一接口(interface)的多个实现,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/19099933/