2011-11-04 5 views
6

Estoy usando el ejemplo de Registry DSL para configurar structuremap. Pero al hacer esto, todos mis tipos registrados están disponibles en todas las capas de mi aplicación, donde agrego una referencia al mapa de la estructura. No quiero que mi capa de negocios sepa nada sobre mi capa de acceso a datos y viceversa. ¿Cómo obtengo structuremap para que solo registre tipos específicos para cada una de mis capas?Structuremap - Cómo registrar ciertos tipos en ciertas capas

Este es el código en mi archivo Global.asax:

ObjectFactory.Initialize(x => 
{ 
    x.AddRegistry<RegistryIOC>(); 
}); 

Y aquí es mi clase RegistryIOC:

public class RegistryIOC : SMRegistry 
{ 

    public RegistryIOC() 
    { 
     For<IProfileService>.Use<ProfileService>(); 
     For<IProctorService>().Use<ProctorService>(); 

     //Business Logic Objects 
     For<IQual>().Use<Qual>(); 
     For<ITest>().Use<Test>(); 
     For<IBoldface>().Use<Boldface>(); 
     For<ITrainingPlan>().Use<TrainingPlan>(); 
     For<IUnit>().Use<Unit>(); 

     //Data Transfer Objects 
     For<IGenericDTO>().Use<GenericDTO>(); 
     For<IProfileDTO>().Use<ProfileDTO>(); 
     For<IQualDTO>().Use<QualDTO>(); 
     For<IPermissionDTO>().Use<PermissionDTO>(); 

     //Repository Objects 
     For<IProctorRepository>().Use<ProctorRepository>(); 
     For<IQualsRepository>().Use<QualsRepository>(); 
     For<ITestRepository>().Use<TestRepository>(); 
     For<IUnitRepository>().Use<UnitRepository>(); 
     For<IUserRepository>().Use<UserRepository>(); 
    } 

} 

Gracias por la ayuda.

+0

¿De qué tipo de capas está hablando? Diferentes procesos? Diferentes máquinas?Si todos se ejecutan en el mismo proceso, probablemente hagas lo que tu capa empresarial sabe * un poco * sobre tu capa de datos, específicamente su interfaz. No está claro qué problema está tratando de resolver. ¿Qué pasa con su clase RegistryIOC? –

+0

Tenemos una capa de servicio, BLL y DAL, que son todos proyectos independientes. Cada proyecto hace referencia a StructureMap. La capa de servicio conoce las otras dos capas, pero el BLL y el DAL no se conocen entre sí. No quiero que otros desarrolladores hagan uso de Business Objects desde dentro del DAL y viceversa. No quiero que los desarrolladores hagan uso de Objetos del repositorio dentro del BLL. La capa de servicio orquesta todo eso. Por lo tanto, al registrar todos los tipos de esta manera, todos los objetos están disponibles en todas nuestras capas (proyectos). –

+0

Bueno, * no * agrega una referencia a StructureMap desde cualquier otra capa que la raíz de composición ... –

Respuesta

3

Uso el reflejo para realizar esta (y otras) tareas. Déjame mostrarte cómo funciona eso.

El primero que hay que hacer es definir una interfaz que nos permite identificar las clases que realizan tareas de inicialización:

public interface IConfigurationTask 
{ 
    void Configure(); 
} 

A continuación, crear una o más clases que implementan esta interfaz. Estas clases se distribuirán en todos sus proyectos, lo cual es otra forma de decir que puede ponerlos "donde pertenecen".

public class RepositoryInitializer : IConfigurationTask 
{ 
    public void Configure() 
    { 
     // code that does relevant initialization goes here 
    } 
} 

La última pieza del rompecabezas es encontrar las clases que implementan la interfaz IConfigurationTask, cree una instancia de ellos y ejecutar el método Configurar. Este es el propósito de la ConfigurationTaskRunner:

public static class ConfigurationTaskRunner 
{ 
    public static void Execute(params string[] assemblyNames) 
    { 
     var assemblies = assemblyNames.Select(Assembly.Load).Distinct().ToList(); 
     Execute(assemblies); 
    } 

    public static void Execute(IEnumerable<Assembly> assemblies) 
    { 
     var tasks = new List<IConfigurationTask>(); 
     assemblies.ForEach(a => tasks.AddRange(a.CreateInstances<IConfigurationTask>())); 

     tasks.ForEach(t => t.Configure()); 
    } 
} 

El código que se muestra aquí utiliza un extensión personalizada para iterar sobre todos los elementos de una lista y ejecutar una acción para cada artículo (el método ParaCada). También estoy usando un reflection library para hacer que la tarea de localizar e instanciar las instancias sea de una sola línea (el método CreateInstances), pero podrías lograr lo mismo usando solo una reflexión simple (como se muestra en el siguiente código).

public static IList<T> CreateInstances<T>(this Assembly assembly) 
{ 
    var query = from type in assembly.GetTypes().Where(t => typeof(T).IsAssignableFrom(t) && typeof(T) != t) 
       where type.IsClass && ! type.IsAbstract && type.GetConstructor(Type.EmptyTypes) != null 
       select (T) Activator.CreateInstance(type); 
    return query.ToList(); 
}  

La última pieza del rompecabezas es activar la ejecución del ConfigurationTaskRunner. Por ejemplo, en una aplicación web esto iría en Application_Start en Global.asax:

// pass in the names of the assemblies we want to scan, hardcoded here as an example 
ConfigurationTaskRunner.Execute("Foo.dll", "Foo.Domain.dll"); 

También he encontrado que es útil con un IPrioritizedConfigurationTask derivados (que añade una característica de prioridad) para permitir la ordenación adecuada de las tareas antes los ejecutas Esto no se muestra en el código de ejemplo anterior, pero es bastante trivial de agregar.

Espero que esto ayude!

+0

En este ejemplo (que es increíble) ¿cómo propone encadenar las dependencias? Si quisiera una instancia de IProdRepo respaldada por ProdCacheRepo respaldada por ProdRepo ... ¿cómo harías ese encadenamiento? ¡Curioso! –

+0

@AndrewSiemer Supongo que esa sería la tarea del marco de trabajo de IoC (en este caso, StructureMap), en función de las configuraciones que le proporcione (en los métodos individuales de Configurar). El código que proporcioné es simplemente un mecanismo de "configuración distribuida" del contenedor IoC (o cualquier otra cosa que necesite inicializar al iniciar la aplicación). –

+0

No puedo hacer uso de la biblioteca de reflexión. Cuando pruebo este código a través de la reflexión regular, a.CreateInstance ("IConfigurationTask"), no obtengo nada como resultado. Tal vez me falta algo en alguna parte ... :-( –

0

Puede crear y configurar múltiples instancias Container independientes y no utilice estática ObjectFactory en absoluto - see this article. Entonces será su responsabilidad proporcionar contenedores adecuados a las capas adecuadas.

Por cierto, ¿cómo desea manejar la comunicación entre capas? ¿No sería de alguna manera difícil? Preferiría dividir los registros (posiblemente para separar ensamblajes) y mantenerlos desacoplados "manualmente" en lugar de forzar el desacoplamiento a nivel de infraestructura.

+0

No me importa cambiar mi implementación actual. Si es mejor tener todos los registros separados para las clases en cada una de mis capas, eso es genial conmigo. Parte de mi problema es que no entiendo completamente cómo "proporcionar contenedores adecuados a las capas adecuadas". ¿Qué es exactamente lo que puse en el cargador global.asax? –

+0

Bueno, generalmente tendrá que tener diferentes puntos de entrada para diferentes capas y cada capa debe tener su propio método de fábrica utilizando el contenedor adecuado: de esta forma tendrá gráficos de objetos separados para cada capa. Pero realmente no veo cómo lograr interacciones entre esos gráficos, por eso es por lo que las preguntas en el segundo párrafo son. Finalmente, debe tener algún tipo de componentes de capa superior X que usen el componente de nivel inferior Y. Si X es de capa media y se crea mediante un contenedor de capa media, también lo es su dependencia Y, aunque sea desde la capa inferior. . – NOtherDev

+0

Por lo general, la respuesta es que es difícil tener gráficos de objetos totalmente desacoplados. Es por eso que sugerí el desacoplamiento en el nivel de registro/ensamblaje, en lugar del nivel de fábrica del objeto. – NOtherDev

Cuestiones relacionadas