Autofac в мультипроектном решении
Я использую Autofac как систему внедрения зависимостей в решении C#, которое охватывает несколько библиотек классов и несколько исполняемых файлов. Я использую модули для настройки Autofac, но это все еще оставляет меня с проблемой построения контейнера DI, который варьируется в зависимости от того, для какого исполняемого файла я его составляю.
Я попытался использовать RegisterAssemblyModules Autofac, но вы должны предоставить ему список сборок для сканирования, и пока не будет использован какой-либо тип в сборке библиотеки классов, сборка не будет загружена и, следовательно, недоступна для сканирования.
Некоторые люди рекомендуют загружать каждую сборку в каталог bin, в котором может быть определение модуля Autofac. Но это, похоже, создает риск того, что нежелательное собрание может быть приведено в действие.
Итак, я придумал этот статический класс, который определен в общей библиотеке классов:
public static class Container
{
private static IContainer _instance;
private static Dictionary<string, Assembly> _moduleAssemblies = new Dictionary<string, Assembly>();
public static void RegisterAutofacModuleAssembly<T>()
where T : class
{
var assembly = typeof(T).Assembly;
if( !_moduleAssemblies.ContainsKey( assembly.FullName ) )
_moduleAssemblies.Add( assembly.FullName, assembly );
}
public static IContainer Instance
{
get
{
if( _instance == null )
{
var builder = new ContainerBuilder();
builder.RegisterAssemblyModules( _moduleAssemblies.Select( ma => ma.Value ).ToArray() );
_instance = builder.Build();
}
return _instance;
}
}
}
Вы используете это, включив такие строки в код запуска приложения:
public static void Main(string[] args)
{
AutoFacRegistrar.Container.RegisterAutofacModuleAssembly<ScannerApp>();
AutoFacRegistrar.Container.RegisterAutofacModuleAssembly<AppConfiguration>();
Это разумное решение? Если есть лучший, более гибкий вариант, мне было бы интересно узнать об этом.
Выпуск в IOptions<>
Связующая система
При реализации предложения @Nightowl888 я столкнулся с проблемой конфигурации Microsoft IOptions<>
система. Вот как я пытаюсь настроить Autofac для разрешения объектов AppConfiguration:
protected override void Load( ContainerBuilder builder )
{
base.Load( builder );
var config = new ConfigurationBuilder()
.AddJsonFile( AppConfiguration.WebJobsConfigFile, false )
.AddUserSecrets<ConfigurationModule>()
.AddEnvironmentVariables()
.Build();
builder.Register<AppConfiguration>( ( c, p ) =>
{
var retVal = new AppConfiguration( c.Resolve<ILogger>() );
config.Bind( retVal );
return retVal;
} )
.SingleInstance();
}
Проблема возникает при вызове Bind(). По мере того, как он просматривает и анализирует информацию о конфигурации, он ожидает создания различных объектов через конструкторы без параметров... что затрудняет использование инжектора конструктора.
Если я не могу использовать инъекцию конструктора, мне нужно иметь возможность разрешить использование контейнера DI в коде конструктора. Я не понимаю, как определить библиотечную сборку, которая не привязана к семантике разрешения конкретного DI-контейнера.
Мысли? Кроме "отказаться от IOptions<>
система ", которую я рассмотрел, но она предоставляет ряд преимуществ, которые я хотел бы сохранить.
1 ответ
Каждое исполняемое приложение должно иметь свою собственную уникальную конфигурацию DI. Библиотеки и фреймворки должны быть построены так, чтобы они были дружественными к DI, но не должны ссылаться на какой-либо DI-контейнер.
Корень композиции - это конфигурация приложения. Совместное использование между приложениями аналогично .config
файл между приложениями - то есть это обычно не делается. См. Повторное использование корня композиции.
Если вы собираетесь использовать модули autofac, они должны быть частью приложения, которое их использует, а не включаться в сборку вместе с компонентами, которые составляются. Хотя может показаться, что вы что-то получаете, не повторяя код конфигурации в каждом приложении, основная проблема заключается в том, что это означает, что ваше приложение потеряло одно из основных преимуществ DI - то есть оно не может обеспечить альтернативная реализация любого данного компонента. Весь смысл создания слабосвязанной библиотеки состоит в том, что она позволяет в конечном итоге принять решение о том, как приложение будет связано вместе, приложением, в котором размещены компоненты.
Pet peeve: Также обратите внимание, что количество ваших проектов или решений не имеет абсолютно никакого отношения к поведению приложения во время выполнения (например, как оно составлено). Проекты и решения - это способ организации кода до его компиляции - после того, как код скомпилирован, не существует понятия "проект" или "решение", все, что вам остается, это "сборки", которые могут зависеть от других "сборок", Для каждого приложения вы получите исполняемую сборку и 0 или более зависимых сборок. Корень композиции должен существовать только в исполняемой сборке.