Внедрение зависимостей ядра 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 параметра.
Ответ 2
Ответ - нет. ASP.NET 5 DI не поддерживает типы с несколькими публичными кон структорами.
Инъекция зависимостей в ядре ASP.NET(vNext)
Инъекция зависимостей в ASP.NET vNext
Ответ 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)
{
}