Зарегистрируйте обратный вызов в 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 непосредственно.

На такие вопросы сложно ответить, потому что есть много способов обойти необходимость построить / перестроить / перестроить контейнер, если вы используете такие преимущества, как лямбда-выражения и параметры - не существует "наилучшей практики", потому что она всегда зависит на ваше приложение и ваши потребности.

Лично я обычно начну с лямбда-подхода.

Другие вопросы по тегам