2012-06-18 6 views
6

Я борюсь с тем, как организовать регистрацию компонентов Autofac в модулях, учитывая, что некоторые из модулей сами имеют зависимости.Модули Autofac со своими зависимостями

Я реализовал абстракцию данных конфигурации (т.е. web.config) в интерфейсе:

interface IConfigurationProvider 
{ 
    T GetSection<T>(string sectionName) 
     where T : System.Configuration.ConfigurationSection; 
} 

вместе с реализациями для ASP.NET (WebConfigurationProvider) и "настольных" приложений (ExeConfigurationProvider) ,

Некоторые из моих autofac модулей, то требуется IConfigurationProvider в качестве параметра конструктора, но некоторые этого не делают:

class DependentModule : Module 
{ 
    public DependentModule(IConfigurationProvider config) 
    { 
     _config = config; 
    } 

    protected override void Load(ContainerBuilder builder) 
    { 
     var configSection = _config.GetSection<CustomConfigSection>("customSection"); 
     builder.RegisterType(configSection.TypeFromConfig); 
    } 

    private readonly IConfigurationProvider _config; 
} 

class IndependentModule : Module 
{ 
    protected override void Load(ContainerBuilder builder) 
    { 
     builder.Register(/* other stuff not based on configuration */); 
    } 
} 

Поскольку метод RegisterType() расширение не принимает регистрации делегата (Func<IComponentContext, T>), как Register() делает , я не могу зарегистрировать IConfigurationProvider до фронта, а затем решить, когда я иду, чтобы зарегистрировать тип, указанный в конфигурации, что-то вроде:

// this would be nice... 
builder.RegisterType(c => c.Resolve<IConfigurationProvider>().GetSection<CustomConfigSection>("sectionName").TypeFromConfig); 

Это означает, что Мне нужно иметь возможность регистрировать модули с и без зависимости от IConfigurationProvider.

Это очевидно, как вручную создать экземпляр каждого модуля и зарегистрировать его:

IConfigurationProvider configProvider = ...; 
var builder = new ContainerBuilder(); 
builder.RegisterModule(new DependentModule(configProvider)); 
builder.RegisterModule(new IndependentModule()); 
using (var container = builder.Build()) 
{ 
    ... 
} 

Но я не хочу, чтобы вручную создать экземпляр мои модули - Я хочу, чтобы сканировать сборки модулей и зарегистрировать их автоматически (как обсуждалось in this question). Поэтому я должен использовать отражение для сканирования сборки для типов IModule и использовать Activator.CreateInstance для создания регистрируемых экземпляров. Но как узнать, следует ли передавать IConfigurationProvider в качестве параметра конструктора. И что происходит, когда другие модули имеют дополнительные или разные зависимости?

Должен быть более простой способ выполнения основной задачи: зарегистрируйте тип, указанный в некоторой конфигурации, предоставляемой через интерфейс, не так ли? Итак, как мне это сделать?

+0

Вы решили это в конце? У меня очень похожий случай, но моя зависимость в свою очередь имеет другую зависимость (я хочу получить конфигурацию из db, поэтому у меня есть IConfigProvider, зависящий от IRepoConfig) – Learner

+0

@Learner, я изначально реализовал что-то, используя комбинацию Autofac и MEF, смоделированных после ответа Джима Боллы ниже, но это было ужасно сложно, и я удалил его слишком долго.У меня больше нет зависимых модулей: поскольку мой основной вариант использования - это выбор, основанный на «типе», с тех пор я принял подход * регистрации * ** всех ** кандидатов, затем * разрешаю * на основе свойство, поступающее из 'ConfigurationSection'. Я могу отправить вам пример кода, если хотите. –

+0

Хорошо, спасибо. Я не думаю, что могу использовать ConfigurationSection/xml в моем случае. – Learner

ответ

6

Вы могли бы сделать что-то вроде этого:

using System.Collections.Generic; 
using System.Linq; 
using Autofac; 
using Autofac.Core; 
using NUnit.Framework; 

namespace Yo_dawg 
{ 
    [TestFixture] 
    public class I_heard_you_like_containers 
    { 
     [Test] 
     public void So_we_built_a_container_to_build_your_container() 
     { 
      var modules = GetModules(); 
      Assert.That(modules.Length, Is.EqualTo(4)); 

      var builder = new ContainerBuilder(); 

      foreach (var module in modules) 
       builder.RegisterModule(module); 

      var container = builder.Build(); 
     } 

     private IModule[] GetModules() 
     { 
      var builder = new ContainerBuilder(); 

      var configurationProvider = new ConfigurationProvider(); 
      builder.RegisterInstance(configurationProvider).AsImplementedInterfaces().ExternallyOwned(); 

      builder.RegisterAssemblyTypes(GetType().Assembly) 
       .Where(t => t.IsAssignableTo<IModule>()) 
       .AsImplementedInterfaces(); 

      using (var container = builder.Build()) 
       return container.Resolve<IEnumerable<IModule>>().ToArray(); 
     } 
    } 

    public class ModuleA : Module 
    { 
     public ModuleA(IConfigurationProvider config) 
     { 
     } 
    } 

    public class ModuleB : Module 
    { 
     public ModuleB(IConfigurationProvider config) 
     { 
     } 
    } 

    public class ModuleC : Module 
    { 
    } 

    public class ModuleD : Module 
    { 
    } 


    public interface IConfigurationProvider 
    { 
    } 

    public class ConfigurationProvider : IConfigurationProvider 
    { 
    } 
} 
+0

Спасибо за ваше предложение. Я преследовал аналогичную стратегию, но мне не нравились некоторые ее аспекты. Мне придется пересмотреть этот подход. –

2

Для этого сценария собственной конфигурации XML Autofac, кажется, чтобы покрыть сценарии вы ориентируетесь. Добавление нового механизма IConfigurationProvider похоже на повторное использование этой функции, уже предоставленной контейнером. Основы документированы по адресу: https://code.google.com/p/autofac/wiki/XmlConfiguration. Синтаксис конфигурации имеет встроенную поддержку модулей.

Существует хорошая альтернатива Пола Стовелла, которая позволяет зарегистрировать модули в коде, но получать параметры из конфигурации - см .: http://www.paulstovell.com/convention-configuration. Надеюсь это поможет!

+0

Спасибо за ответ, но я не понимаю, как выражать мою конфигурацию Autofac в XML помогает мне в этом сценарии. Возможно, потому, что я немного испортил код в моем вопросе и который я только что отредактировал, чтобы лучше выразить мысль о том, что я пытаюсь работать с пользовательскими типами SectionHandler. –

Смежные вопросы