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 или более зависимых сборок. Корень композиции должен существовать только в исполняемой сборке.

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