2

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

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

public interface IStatistics
{
    Statistics GetStatistics();
}

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

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

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

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

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

  1. 页面上有5个不同的参数,每个参数指向一个组件
  2. 使用不同的名称在容器上注册每个实现
  3. 在容器上显式注册我的网络表单,并使用自定义 InjectionConstructor 以正确的顺序为页面注入方法指定每个注册的接口

我知道 Unity 有一个 ResolveAll 方法,因此允许一个人接收IStatistics[]or IEnumerable<IStatistics>,但是我将无法区分它们。

我认为MEF用元数据接口的概念很好地解决了这个问题。也许在这方面进行 MEF 将是解决此问题的一种方法?我认为这里不合适,因为这些是我们正在谈论的 wcf 代理,我根本看不出这将如何与 MEF 集成。

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

4

1 回答 1

2

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

这是一个想法,它可能更直接,可以满足您的需求,同时保持可维护性和可扩展性,特别是如果您在某些时候需要为每种组件类型提供不同的实现:

UML

DefaultStatisticsProvider组件可以使用它来实现IStatisticsProvider接口。这里不涉及 DI,因为实现在 common 项目中可用。

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

于 2013-10-01T07:23:20.257 回答