使用DI传递相同接口的多个实现

时间:2013-09-30 17:10:15

标签: .net wcf dependency-injection unity-container mef

我们公司的一个产品由许多小型网络应用程序和一个Windows服务组件组成,每个组件都可能驻留在不同的计算机上。其中一个是WebForms项目,它作为所有其他项目的配置中心。

我们现在正在设计一个功能来公开组件的一般信息。想象一下像这样的简单界面:

public interface IStatistics
{
    Statistics GetStatistics();
}

我们希望在所有组件上使用相同的接口,因此这是集中在一个通用的共享程序集上。实现最初也是相同的,因此它与接口一起位于同一个程序集中。

然后,我们的想法是使用公共程序集上的实现和接口在每个组件上公开Wcf服务。该实现使用环境类,根据它们的运行位置返回不同的东西,如本地机器时间。

我想优雅地解决的问题是如何使用相同的界面将每个组件的所有实现传递给webform。

我们目前使用Unity,但我想我会遇到与任何其他DI解决方案相同的问题。我想为这个相同的接口注入5个实现(每个组件一个),并且能够按组件区分它们(想一个Dictionary<Component, IStatistics>,其中ComponentEnum)。这是必需的,因为页面上会有一个下拉列表,用于选择哪个组件的信息是可见的,然后页面将调用正确的实现来检索结果。

我知道我可以为所有实现使用命名注册,然后注入它们。不幸的是,这会让我:

  1. 页面上有5个不同的参数,每个参数都指向一个组件
  2. 使用不同的名称注册容器上的每个实现
  3. 在容器上显式注册我的webform,并使用自定义的InjectionConstructor以正确的顺序为页面注入方法指定每个注册的接口
  4. 我知道Unity有一个ResolveAll方法,因此允许我们接收IStatistics[]IEnumerable<IStatistics>,但之后我将无法区分它们。

    我认为MEF使用元数据接口的概念精辟地解决了这个问题。也许MEF就此解决这个问题?我认为这不合适,因为这些是我们正在谈论的wcf代理,我看不出它会如何与MEF整合。

    也许使用工厂会是一个更好的策略,但我也没有看到我如何在工厂注入服务,所以问题会持续存在。

1 个答案:

答案 0 :(得分:2)

我想知道,你是否可以设计整个事情略有不同。我认为你要做的是与IoC有关的一点点。如果我理解正确,你需要五个相同类型的实例,你可以以某种方式与不同类型的其他五个对象相关联。 'IStatistics'是在通用程序集中定义的接口。实现,比如说Statistics在同一个程序集中。不同类型的五个实例在它们自己的“本地”程序集中定义,这些程序集由DI解析而不是直接引用。

这个想法可能更简单,可以实现您的需求,同时保持可维护性和可扩展性,特别是如果您在某些时候需要针对每种组件类型实现不同的实现:

UML

组件可以使用

DefaultStatisticsProvider来实现IStatisticsProvider接口。这里没有涉及DI,因为实现在公共项目中可用。

public class DefaultStatisticsProvider : IStatisticsProvider
{
    public Statistics GetStatistics()
    {
        var statistics = new Statistics();
        // Generate statistics data
        return statistics;
     }
} 

组件直接实现IStatisticProvider并将方法转发到类型DefaultStatisticsProvider的私有字段,它们在构造函数中初始化:

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()的实现。

相关问题