.net - 使用 DI 传递同一接口(interface)的多个实现

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

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

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

public interface IStatistics
{
    Statistics GetStatistics();
}

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

我们的想法是在每个组件上公开一个 Wcf 服务,同时使用公共(public)程序集上的实现和接口(interface)。该实现使用环境类,根据运行位置返回不同的内容,例如本地机器时间。

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

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

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

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

我知道 Unity 有一个 ResolveAll 方法,因此允许接收 IStatistics[]IEnumerable<IStatistics> ,但这样我就无法区分它们了。

我认为MEF通过元数据接口(interface)的概念很好地解决了这个问题。也许让 MEF 来解决这个问题?我认为这里不合适,因为我们正在谈论这些 wcf 代理,我根本看不出这将如何与 MEF 集成。

也许使用工厂是一个更好的策略,但我不知道如何在工厂上注入(inject)服务,所以问题仍然存在。

最佳答案

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

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

UML

组件可以使用

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/

相关文章:

unit-testing - 使用 RequireJS、Jasmine 和测试的 JavaScript 依赖注入(inject)

.net - 团结 : how to resolve class through base interface

c# - 如何在桌面上获得与 IIS7 处理交互的许可?

wcf - 在 Debug模式下以编程方式设置 WCF 超时

c# - 使用 BitConverter 在 C# 中进行快速转换,它能更快吗?

c# - 对简单类型使用结构而不是类

c# - WCF 模拟不是模拟管理员

java - @Autowired 失败 - java.lang.ClassCastException

c# - 如果我调用 C# 事件处理程序并调用它,会发生什么情况?

c# - 将复杂(嵌套)JSON 反序列化为 C# 对象