Внедрение зависимостей ядра ASP.NET с несколькими конструкторами

У меня есть помощник тегов с несколькими конструкторами в моем приложении ASP.NET Core. Это приводит к следующей ошибке во время выполнения, когда ASP.NET 5 пытается разрешить тип:

InvalidOperationException: несколько конструкторов, принимающих все данные типы аргументов, были найдены в типе "MyNameSpace.MyTagHelper". Должен быть только один применимый конструктор.

Один из конструкторов не имеет параметров, а другой имеет несколько аргументов, параметры которых не являются зарегистрированными типами. Я хотел бы использовать конструктор без параметров.

Есть ли какой-нибудь способ получить инфраструктуру внедрения зависимостей ASP.NET 5 для выбора конкретного конструктора? Обычно это делается с помощью атрибута, но я ничего не могу найти.

Мой пример использования - я пытаюсь создать один класс, который будет и TagHelper, и HTML-помощником, что вполне возможно, если эта проблема будет решена.

Ответ 1

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

services.AddScoped<IService>(provider => {
    var dependency = provider.GetRequiredService<IDependency>();

    // You can select the constructor you want here.
    return new Service(dependency, "my string parameter");
});

Примечание: поддержка нескольких конструкторов была добавлена в более поздних версиях, как указано в других ответах. Теперь стек DI удачно выберет конструктор с большинством параметров, которые он может разрешить. Например, если у вас есть 2 конструктора - один с 3 параметрами, указывающими на сервисы, а другой с 4 - он предпочтет тот, у которого 4 параметра.

Ответ 3

Ответ ASP.NET Core 1.0

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

Если у вас есть два конструктора с аргументами, поведение заключается в использовании первого конструктора соответствия, в котором известны параметры. Вы можете посмотреть исходный код для класса ConstructorMatcher для деталей здесь.

Ответ 4

Основной ответ ASP.NET

У меня появилось следующее обходное решение, пока они не исправят/не улучшат это.

Во-первых, объявите только одного конструктора в вашем контроллере (передавая только нужные параметры конфигурации), учитывая, что объекты настроек, переданные в конструкторе, могут быть нулевыми (.NET Core будет автоматически вводить их, если вы настроите их в методе Startup)

public class MyController : Controller
{
    public IDependencyService Service { get; set; }

    public MyController(IOptions<MySettings> settings)
    {
        if (settings!= null && settings.Value != null)
        {
            Service = new DependencyServiceImpl(settings.Value);
        }
    }
}

Затем в ваших методах тестирования вы можете создать экземпляр контроллера двумя способами:

  • Отказывание объекта IOptions при конструировании тестируемого объекта
  • Построить передачу нулевого значения во всех параметрах, а затем Заблокировать зависимость, которую вы будете использовать в своих тестах. После этого у вас есть пример:
[TestClass]
    public class MyControllerTests
    {
        Service.Controllers.MyController controller;
        Mock<IDependencyService> _serviceStub;

        [TestInitialize]
        public void Initialize()
        {
            _serviceStub = new Mock<IDependencyService>();
            controller = new Service.Controllers.MyController(null);
            controller.Service = _serviceStub.Object;
        }
    }

С этого момента вы можете иметь полное тестирование с инъекцией зависимостей и высмеивать готовые в .NET Core.

Надеюсь, что это поможет

Ответ 5

ASP.NET Core 2.1 и выше

Вы можете использовать ActivatorUtilitiesConstructorAttribute в конструкторе, который вы хотите использовать в DI:

[ActivatorUtilitiesConstructor]
public MyClass(ICustomDependency d)
{
}