Зарегистрируйте обратный вызов в Autofac и снова создайте контейнер в обратном вызове
У меня есть основное приложение dotnet. мой Startup.cs
регистрирует типы / реализации в Autofac. Для одной из моих регистраций требуется предыдущий доступ к услуге.
var containerBuilder = new ContainerBuilder();
containerBuilder.RegisterSettingsReaders(); // this makes available a ISettingsReader<string> that I can use to read my appsettings.json
containerBuilder.RegisterMyInfrastructureService(options =>
{
options.Username = "foo" //this should come from appsettings
});
containerBuilder.Populate(services);
var applicationContainer = containerBuilder.Build();
Дилемма к тому времени, когда я должен .RegisterMyInfrastructureService
Мне нужно иметь в наличии ISettingsReader<string>
это было зарегистрировано только ранее (контейнер Autofac еще не был построен).
Я читал о регистрации с помощью обратного вызова для выполнения чего-либо после того, как контейнер autofac был построен. Так что я мог бы сделать что-то вроде этого:
builder.RegisterBuildCallback(c =>
{
var stringReader = c.Resolve<ISettingsReader<string>>();
var usernameValue = stringReader.GetValue("Username");
//now I have my username "foo", but I want to continue registering things! Like the following:
containerBuilder.RegisterMyInfrastructureService(options =>
{
options.Username = usernameValue
});
//now what? again build?
});
но проблема в том, что после того, как я хочу использовать сервис, я не делаю что-то вроде запуска сервиса или чего-то подобного, а продолжаю регистрировать вещи, для которых требовались настройки, которые я теперь могу предоставить.
Могу ли я просто позвонить снова builder.Build()
в конце моего обратного вызова, чтобы контейнер просто перестраивался без каких-либо проблем? Это кажется немного странным, потому что сборщик уже был собран (поэтому был выполнен обратный вызов).
Какой лучший способ справиться с этой дилеммой с помощью автофака?
ОБНОВЛЕНИЕ 1: Я прочитал, что такие вещи, как builder.Update(), теперь устарели, потому что контейнеры должны быть неизменными. Что подтверждает мое подозрение, что создание контейнера, добавление новых регистраций и повторное построение не является хорошей практикой.
Другими словами, я могу понять, что использование обратного вызова для построения реестра не должно использоваться для регистрации дополнительных вещей. Но тогда остается вопрос: как бороться с этими проблемами?
1 ответ
Этот вопрос обсуждения многое объясняет, включая способы обойти необходимость обновления контейнера. Я подведу итоги здесь, но в этом выпуске много информации, которую не имеет смысла пытаться повторить повсюду.
- Ознакомьтесь со всеми способами регистрации компонентов и передачи параметров. Не забывайте о таких вещах, как разрешенные параметры, модули, которые могут динамически размещать параметры, и так далее.
- Лямбда-регистрации решают почти все эти проблемы, которые мы видели. Если вам нужно зарегистрировать что-то, что обеспечивает конфигурацию, а затем использовать эту конфигурацию как часть другой регистрации - лямбды будут огромными.
- Рассмотрим промежуточные интерфейсы, такие как создание
IUsernameProvider
это поддерживаетсяISettingsReader<string>
,IUsernameProvider
может быть лямбда (разрешить некоторые настройки, прочитать конкретную и т. д.), а затем нижестоящие компоненты могут принятьIUsernameProvider
непосредственно.
На такие вопросы сложно ответить, потому что есть много способов обойти необходимость построить / перестроить / перестроить контейнер, если вы используете такие преимущества, как лямбда-выражения и параметры - не существует "наилучшей практики", потому что она всегда зависит на ваше приложение и ваши потребности.
Лично я обычно начну с лямбда-подхода.