Pregunta

Aunque esta pregunta está relacionada con StructureMap, mi pregunta general es:

  

Al cablear componentes con una IoC   contenedor en el código (como opuesto   a la configuración a través de xml )   Generalmente se necesita un proyecto / construcción explícita   referencias a todos los ensamblajes?

¿Por qué los ensambles separados? Porque:


  

" Clases abstractas que residen en un   montaje separado de su hormigón   Las implementaciones son una gran manera de   lograr tal separación. - Marco   Pautas de diseño p.91


Ejemplo:

Digamos que tengo PersonBase.dll y Bob.dll

Bob hereda de la clase abstracta PersonBase . Ambos están en el espacio de nombres Persona . Pero en diferentes ensamblajes .

Estoy programando para PersonBase , no para Bob .

De vuelta en mi código principal, necesito una persona. StructureMap puede escanear ensamblajes. ¡Genial, le pediré a StructureMap uno!

Ahora, en mi código principal, por supuesto me refiero solo a PersonBase , no a Bob . En realidad, no quiero que mi código sepa nada sobre Bob . Sin referencias de proyecto, sin nuthin. Ese es todo el punto.

Por eso quiero decir:

//Reference: PersonBase.dll (only)
using Person;  
...

//this is as much as we'll ever be specific about Bob:
Scan( x=> { x.Assembly("Bob.dll"); }

//Ok, I should now have something that's a PersonBase (Bob). But no ?
ObjectFactory.GetAllInstances<PersonBase>().Count == 0

Sin suerte. Lo que sí funciona es que explícito que quiero a Bob:

//Reference: PersonBase.dll and Bob.dll
using Person; 
...
Scan( x => {x.Assembly("Bob.dll"); }

//If I'm explicit, it works. But Bob's just a PersonBase, what gives?
ObjectFactory.GetAllInstances<Bob>().Count == 1 //there he is!

Pero ahora he tenido que hacer referencia a Bob.dll en mi proyecto, que es exactamente lo que no quería.

Puedo evitar esta situación usando la configuración de Spring + Xml. Pero luego vuelvo a la configuración de Spring + Xml ...!

  

¿Me estoy perdiendo algo al usar   StructureMap, o como un general   principio, hacer (fluido) IoC   las configuraciones necesitan referencias explícitas   a todas las asambleas?

Pregunta posiblemente relacionada: StructureMap y ensamblajes de escaneo

¿Fue útil?

Solución

Finalmente conseguí esto resuelto. Se parece a esto:

IoC Uml http://img396.imageshack.us/img396/1343/iocuml. jpg

con las asambleas

  • Core.exe
  • PersonBase.dll (referenciado tiempo de compilación por Core.exe)
  • Bob.dll ( tiempo de ejecución cargado a través de StructureMap Scan)
  • Betty.dll ( tiempo de ejecución cargado a través de StructureMap Scan)

Para obtenerlo con StructureMap, necesitaba un personalizado "ITypeScanner" para admitir la exploración de ensamblajes:

public class MyScanner : ITypeScanner {
  public void Process(Type type, PluginGraph graph) {

    if(type.BaseType == null) return;

    if(type.BaseType.Equals(typeof(PersonBase))) {
      graph.Configure(x => 
        x.ForRequestedType<PersonBase>()
        .TheDefault.Is.OfConcreteType(type));
    }
  }
} 

Entonces mi código principal se ve así:

ObjectFactory.Configure(x => x.Scan (
  scan =>
  {
    scan.AssembliesFromPath(Environment.CurrentDirectory 
    /*, filter=>filter.You.Could.Filter.Here*/);

    //scan.WithDefaultConventions(); //doesn't do it

    scan.With<MyScanner>();
  }
));

ObjectFactory.GetAllInstances<PersonBase>()
 .ToList()
  .ForEach(p => 
  { Console.WriteLine(p.FirstName); } );

Otros consejos

También puede hacer la configuración xml con StructureMap. Incluso puedes mezclarlos si quieres.

También hay atributos de StructureMap que podrías poner en tu clase de Bob para decirle a StructureMap cómo cargar el ensamblaje. DefaultConstructor es uno que termino usando de vez en cuando.

La opción de exploración automática solo funciona cuando se mantienen las convenciones de nomenclatura, ensamblaje y espacio de nombres. Puede configurar de forma manual el mapa de estructura con una interfaz fluida. Ejemplo:

ObjectFactory.Initialize(initialization => 
   initialization.ForRequestedType<PersonBase>()
    .TheDefault.Is.OfConcreteType<Bob>());

Lo que hacemos en mi proyecto actual (que usa AutoFac, no StructureMap, pero creo que no debería marcar la diferencia):

Tenemos las interfaces que definen los servicios externos que la aplicación utiliza en un ensamblaje central, digamos App.Core (como su PersonBase).

Luego tenemos las implementaciones de estas interfaces en Services.Real (como Bob.dll).

En nuestro caso, también tenemos Service.Fake , que se utilizan para facilitar las pruebas de UI con dependencias en otros servicios y bases de datos empresariales, etc.

El front-end " cliente " la aplicación en sí (en nuestro caso, la aplicación ASP.NET MVC) hace referencia a App.Core .

Cuando se inicia la aplicación, usamos Assembly.Load para cargar los "Servicios" apropiados. DLL de implementación, basada en una configuración de configuración.

Cada una de estas DLL tiene una implementación de IServiceRegistry que devuelve una lista de los servicios que implementa:

public enum LifestyleType { Singleton, Transient, PerRequest}

public class ServiceInfo {
    public Type InterfaceType {get;set;}
    public Type ImplementationType {get;set;}
    // this might or might not be useful for your app, 
    // depending on the types of services, etc.
    public LifestyleType Lifestyle {get;set;} 
}

public interface IServiceRegistry {
    IEnumerable<ServiceInfo> GetServices();
}

... la aplicación encuentra este ServiceRegistry a través de la reflexión y enumera a través de estas instancias de ServiceInfo y las registra en el contenedor. Para nosotros, este registro de todos los servicios vive en la aplicación web, pero es posible (y preferible en muchos casos) tenerlo en un ensamblaje separado.

De esta forma podemos aislar la lógica del dominio del código de infraestructura y evitar "solo por esta vez". soluciones alternativas donde la aplicación termina dependiendo de una referencia directa al código de infraestructura. También evitamos tener que tener una referencia al contenedor en cada implementación de Servicios.

Una cosa realmente importante si está haciendo esto: asegúrese de asegurarse de que tiene pruebas que verifiquen que puede crear cada " nivel superior " escriba (en nuestro caso, Controladores ASP.NET MVC) con cada configuración potencial del contenedor IOC.

De lo contrario, es bastante fácil olvidar implementar una interfaz y romper grandes secciones de su aplicación.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top