2012-06-18 24 views
6

Estoy luchando con la forma de organizar mis registros de componentes Autofac en módulos dado que algunos de los módulos tienen dependencias.Módulos Autofac con sus propias dependencias

he implementado una abstracción de datos de configuración (es decir web.config) en una interfaz:

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

junto con implementaciones para ASP.NET (WebConfigurationProvider) y aplicaciones "escritorio" (ExeConfigurationProvider) .

Algunos de mis módulos autofac continuación, requieren una IConfigurationProvider como un parámetro de constructor, pero algunos no lo hacen:

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 */); 
    } 
} 

Dado que el método RegisterType() extensión no acepta un delegado de registro (Func<IComponentContext, T>), al igual que lo hace Register() , no puedo registrar el IConfigurationProvider por adelantado y luego resolverlo cuando voy a registrar el tipo especificado en la configuración, algo así como:

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

Esto significa que Necesito poder registrar los módulos con y sin una dependencia en IConfigurationProvider.

Es obvio cómo crear una instancia de forma manual cada módulo y registrarlo:

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

Pero no desea crear una instancia manualmente mis módulos - Quiero escanear montajes de módulos y registrar de forma automática (como se discutió in this question) Así que tengo que usar la reflexión para escanear el ensamblaje para los tipos IModule, y usar Activator.CreateInstance para hacer instancias registrables. Pero, ¿cómo sé si pasar o no un IConfigurationProvider como parámetro de constructor? ¿Y qué sucede cuando otros módulos tienen dependencias adicionales o diferentes?

Tiene que haber una forma más directa de llevar a cabo la tarea básica: registrar un tipo especificado en alguna configuración proporcionada a través de una interfaz, ¿verdad? Entonces, ¿cómo hago eso?

+0

¿Resolviste esto al final? Tengo un caso muy similar, pero mi dependencia está teniendo otra dependencia (quiero obtener config de db, entonces tengo un IConfigProvider dependiente de IRepoConfig) – Learner

+0

@Learner, originalmente implementé algo usando una combinación de Autofac y MEF modelado después de la respuesta de Jim Bolla a continuación, pero fue tremendamente compleja y la retiré antes de que pase demasiado tiempo.Ya no tengo módulos dependientes: dado que mi caso de uso primario fue la selección basada en un "Tipo", desde entonces he tomado el enfoque de * registrar * ** todos ** los candidatos, luego * resolver * basado en el propiedad proveniente de 'ConfigurationSection'. Puedo enviarte código de muestra si lo deseas. –

+0

Ok, gracias. No creo que pueda usar ConfigurationSection/xml en mi caso. – Learner

Respuesta

6

se podría hacer algo como esto:

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

Gracias por su sugerencia. Seguí una estrategia similar, pero no me gustaron ciertos aspectos. Tendré que volver a visitar este enfoque. –

2

Para este escenario, la propia configuración XML de Autofac parece cubrir los escenarios de orientación. Agregar un nuevo mecanismo IConfigurationProvider parece reinventar esta funcionalidad ya provista por el contenedor. Los conceptos básicos están documentados en: https://code.google.com/p/autofac/wiki/XmlConfiguration. La sintaxis de configuración tiene soporte integrado para módulos.

Hay una buena alternativa de Paul Stovell que permite que los módulos se registren en el código pero que reciban los parámetros desde config - vea: http://www.paulstovell.com/convention-configuration. ¡Espero que esto ayude!

+0

Gracias por la respuesta, pero no entiendo cómo expresar mi configuración de Autofac en XML me ayuda en este escenario. Tal vez porque cometí un error grave en el código de mi pregunta, y que acabo de editar para expresar mejor la idea de que estoy tratando de trabajar con tipos personalizados de SectionHandler. –

Cuestiones relacionadas