Две реализации одного и того же интерфейса в конфигурации JSON Autofac - PullRequest
0 голосов
/ 21 февраля 2019

Мне нужно включить позднюю привязку в приложении, и я хочу иметь возможность явно настраивать службы с использованием файла конфигурации JSON.

У меня есть интерфейс IDependency и два класса DependencyOne и DependencyTwo, которые оба реализуют интерфейс.У меня также есть класс SomeService, в котором есть конструктор со следующей подписью:

public SomeService(IDependency dependency1, IDependency dependency2)

Я хочу ввести DependencyOne для dependency1 и DependencyTwo для dependency2.

Как я могу настроить это исключительно в конфигурации JSON, без использования каких-либо атрибутов в коде?Это вообще возможно?

Требование об отсутствии атрибутов необходимо, поскольку сборка с поздним связыванием не должна зависеть от AutoFac.

Заранее спасибо.

Обновление: решение

Ответ Travis ниже содержит ссылку на FAQ, которая привела меня к приемлемому решению.Используйте «маркерные» интерфейсы, например, IDependencyOne : IDependency и IDependencyTwo : IDependency, а затем SomeService(IDependencyOne dependency1, IDependencyTwo dependency2).Мне не очень нравится то, что теперь универсальный декоратор для IDependency должен реализовать все маркеры, скажем LoggingDecorator : IDependencyOne, IDependencyTwo, если я хочу использовать его в SomeService, но пока маркеры остаются пустыми, этоне большая проблема.Таким образом, мне не нужно навязывать зависимости от dll-файлов Autofac в сборке с поздним связыванием, хотя в файле JSON по-прежнему настроен DI.

1 Ответ

0 голосов
/ 22 февраля 2019

Если у вас есть две разные реализации одного и того же интерфейса, которые нельзя обрабатывать одинаково, это запах кода. Часто задаваемые вопросы о способах обхода этой проблемы , но краткий ответ: , вы не сможете буквально указать два разных экземпляра одного и того же интерфейса, как это, без некоторой ручной работы. Не существует механизма для легкого подключения, потому что это проблема дизайна.

Найдите время, чтобы прочитать FAQ , чтобы узнать, почему и дополнительные идеи о том, как решить эту проблему, помимо того, чтоЯ показываю здесь.

Однако, давайте предположим, что вы не можете изменить интерфейс IDependency, поскольку обычно это является камнем преткновения для людей.Давайте также предположим, что вы не можете просто поместить DependencyOne и DependencyTwo прямо в конструктор по ... любой причине.(И то, и другое было бы первым местом, где я бы попытался решить эту проблему, а не пытался усложнить мою работу с DI, но, опять же, скажем, ради аргумента, что это не вариант.)

Iвероятно, зарегистрирует каждый экземпляр в config с ключом метаданных, который можно будет использовать позже.

{
  "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"
    }]
  }]
}

ОК, поэтому у нас есть два компонента, каждый из которых предоставляет один и тот же интерфейс, и каждый из них имеет ключ метаданных Oneили Two соответственно.

В вашем классе вы можете использовать эти метаданные.

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();
  }
}

Идея состоит в том, что вы можете выбрать подходящую вещь, используя метаданные.Очевидно, приспособить это к вашим собственным потребностям;возможно, это не параметр от вызывающей стороны, а что-то в вашем коде в другом месте;концепция остается в силе.

Опять же, я не могу рекомендовать достаточно сильно, чтобы вы ознакомились с FAQ и настоятельно рассмотрели возможность редизайна, чтобы полностью избежать этой ситуации ,В конечном итоге это облегчит вашу жизнь и жизнь ваших коллег-разработчиков.

...