Autofac的JSON配置中相同接口的两种实现

时间:2019-02-21 12:16:18

标签: autofac autofac-configuration

我需要在应用程序中启用后期绑定,并且希望有一个使用JSON配置文件显式配置服务的选项。

我有一个接口IDependency和两个类DependencyOneDependencyTwo都实现了该接口。我还有一个SomeService类,该类具有带有以下签名的构造函数:

public SomeService(IDependency dependency1, IDependency dependency2)

我想为DependencyOne注入dependency1,为DependencyTwo注入dependency2

如何在不使用代码中任何属性的情况下仅以JSON配置进行配置?有可能吗?

需要无属性要求,因为后期绑定程序集不应该依赖于AutoFac。

谢谢。

更新:解决方案

Travis在下面的回答包含指向FAQ的链接,该链接使我找到了可接受的解决方案。使用“标记”界面,例如IDependencyOne : IDependencyIDependencyTwo : IDependency,然后SomeService(IDependencyOne dependency1, IDependencyTwo dependency2)。我不太喜欢的是,现在IDependency的通用修饰符需要实现所有标记,如果要在LoggingDecorator : IDependencyOne, IDependencyTwo中使用它,请说SomeService,但是只要标记保持空白,这不是什么大问题。这样,我不必在后期绑定程序集中强制依赖于Autofac的dll,而仍然可以在JSON文件中配置DI。

1 个答案:

答案 0 :(得分:0)

如果同一接口有两种不同的实现方式,不能一视同仁,那就是代码的味道。 There is an FAQ about ways to work around that,但简单的答案是如果没有一些人工操作,您将无法从字面上指定相同接口的两个不同实例。没有一种机制可以轻松地对此进行连接因为这是一个设计问题。

请花些时间阅读the FAQ,以了解为什么以及除我在此显示的内容以外的其他解决方法。

但是,假设您不能更改界面IDependency,因为通常这是人们的症结所在。我们还要假设,出于某种原因,您不能仅将DependencyOneDependencyTwo放在构造函数中。 (这两个都是我希望解决此问题的第一位,而不是试图使我的DI接线复杂化,但是再次,让我们说一下,这不是一个选择。)

我可能会使用元数据密钥在配置中注册每个实例,以便以后使用。

{
  "components": [{
    "type": "MyAssembly.DependencyOne, MyAssembly",
    "services": [{
      "type": "MyAssembly.IDependency, MyAssembly"
    }],
    "metadata": [{
      "key": "type",
      "value": "One",
      "type": "System.String, mscorlib"
    }]
  }, {
    "type": "MyAssembly.DependencyTwo, MyAssembly",
    "services": [{
      "type": "MyAssembly.IDependency, MyAssembly"
    }],
    "metadata": [{
      "key": "type",
      "value": "Two",
      "type": "System.String, mscorlib"
    }]
  }]
}

好的,因此我们有两个组件,每个组件都公开相同的接口,并且每个组件分别具有OneTwo的元数据键。

In your class you can use that metadata.

public class SomeService
{
  readonly IEnumerable<Meta<IDependency>> _dependencies;

  public SomeService(IEnumerable<Meta<IDependency>> dependencies)
  {
    _dependencies = dependencies;
  }

  public void DoSomething(string parameter)
  {
    var dep = _dependencies.First(a => a.Metadata["type"].Equals(parameter));
    dep.DoSomething();
  }
}

想法是您可以使用元数据选择适当的内容。显然可以根据自己的需要进行调整;也许这不是调用者的参数,而是其他地方的代码;这个概念仍然成立。

不过,我仍然不能强烈建议您check out the FAQ强烈考虑进行重新设计,以完全避免这种情况。从长远来看,它将使您的生活和其他开发人员的生活更加轻松。