Параметры автозапуска во время выполнения
Я новичок в autofac и ищу лучшие практики по передаче значений времени выполнения в конструктор. Я прочитал кучу вопросов о стековом потоке, где они задаются, но ни один из них полностью не раскрыт. Должны ли мы использовать делегатов, фабрику для создания сервиса и т. Д. Я знаю, что передача контейнера - не лучший способ сделать это.
В моем конкретном случае у меня есть служба, которая имеет доступ к нескольким зависимостям, например, ведение журнала, поставщик данных и т. Д. Наряду с несколькими передаваемыми службами у меня также есть параметры времени выполнения, которые мне нужно записать, скажем, идентификатор пользователя, пароль. Идентификатор пользователя и пароль требуются для SomeService и ищутся, когда веб-программа просмотра выполняет определенное действие. Ниже то, что я имею, и подчеркнуло проблему.
public class SomeService : ISomeService
{
private readonly IDataProvider _dataProvider;
private readonly ILog _log;
private readonly string _username;
private readonly string _password;
public SomeService(IDataProvider dataProvider, ILog log,
string username, string password)
{
_dataProvider = dataProvider;
_log = log;
_username = username;
_password = password;
}
}
Поставщик данных и журнал настраиваются в режиме автозапуска
builder.RegisterType<DataProviderService>().As<IDataProvider>()
builder.RegisterType<SomeLogService>().As<ILog>()
Большая часть функциональности этого "SomeService" требует имени пользователя и пароля для проверки перед выполнением задач, поэтому решил, что лучше всего перейти в конструктор при создании, но никогда не сталкивался с требованиями времени выполнения для autofac. Я рассмотрел вопрос Autofac - разрешение параметров времени выполнения без необходимости передавать контейнер, и он кажется близким к тому, что мне нужно, но мне нужно больше отзывов о том, как это можно сделать.
2 ответа
В общем, вы должны предотвратить передачу значений времени выполнения в конструкторы. Это сильно усложнит ваш дизайн и вашу конфигурацию DI. Конструкторы предназначены для зависимостей и значений конфигурации. Передайте значения времени выполнения через аргументы метода или внедрите сервис, который позволяет вам получить эти значения времени выполнения. Возьмите например IUserContext
сервис, позволяющий получить имя текущего вошедшего в систему пользователя.
AutoFac поддерживает разрешение служб с параметрами времени выполнения посредством концепции параметризованного создания экземпляров.
В конструкторе клиента с зависимостью от службы с конкретными параметрами времени выполнения объявите свою зависимость как Func
который возвращает эту зависимость в терминах своих строго типизированных параметров.
Например Func<string, ISomeService> myService
Когда AutoFac видит Func
он создает делегат, который действует как фабричный метод для создания сервиса.
Из документации:
Если тип T зарегистрирован в контейнере, Autofac автоматически разрешит зависимости от Func как фабрики, которые создают экземпляры T через контейнер.
Невозможно иметь дубликаты типов в списке параметров вашей зависимости, как в случае ISomeService
в вашем вопросе. Например Func<string, string, ISomeService>
не будет работать. В этом случае вам необходимо указать собственную фабрику делегатов.
Из документации:
Фабричные адаптеры предоставляют функции создания экземпляров контейнера для управляемых компонентов, не подвергая их воздействию самого контейнера.
Одним из способов реализации этого подхода является объявление типа делегата вместе с определением вашего типа, которое AutoFac будет использовать в качестве фабричного метода.
Например
public class SomeService : ISomeService
{
// Factory method
public delegate SomeService Factory(string userName, string password);
public SomeService(IDataProvider dataProvider,
ILog log,
string username,
string password)
{
// ..
Ваш клиент ISomeService будет выглядеть следующим образом:
public class MyClient
{
public MyClient(SomeService.Factory serviceFactory)
{
// Resolve ISomeService using factory method
// passing runtime parameters
_myService = serviceFactory("this", "that");
}
}
Обратите внимание, что все параметры, не связанные со временем выполнения, для службы (в вашем случае IDataProvider и ILog) продолжают автоматически разрешаться контейнером.