2011-03-01 12 views
6

Soy un principiante que lucha con IoC y DI. Me gustaría poder resolver la conexión y la fábrica de conexión de forma dinámica utilizando autofac (o cualquier otra herramienta .oC IOC adecuada).IoC, fábricas y argumentos de constructor

Un escenario podría cambiar la aplicación de conexión a otro con más instalaciones para el rastreo etc.

Cuando aplico DI y de la COI para el código de abajo, aparece un lío de namedParameter en los constructores etc. La fábrica de conexiones devuelve una nueva conexión con un puerto único (ejemplo tonto, solo para mostrar que necesito mantener algún tipo de estado en la fábrica)

Me imagino que podría usar inyección de propiedad para el rango de IP y puerto, pero de esa manera, no se garantiza que las conexiones tengan una IP o puerto, que es el punto de un constructor. Además, los parámetros nombrados también me hacen depender de los nombres de los argumentos.

Ideas, patrones, punteros IoC son muy apreciados!

Actualización:

más específica: ¿Cómo podría cambiar la clase de conexión que se inyectable? ¿Debería ir con la inyección de propiedad? ¿O algún truco que podría hacer para obtener una resolución más segura de tipos con argumentos de constructor?

public interface IConnection { 
    void Open(); 
    void Close(); 
    string Execute(string command); 
} 

public interface IConnectionFactory { 
    IConnection CreateConnection(); 
} 

public class Connection : IConnection { 
    ... 
    public Connection(String ip, int port) { 
    _ip = ip; 
    _port = port; 
    } 

    public string Execute() {} 
    public void Open() {} 
    public void Close() {} 
} 


public class ConnectionFactory : IConnectionFactory { 
    //How would I resolve this? 
    public ConnectionFactory(string ip, int fromPort) { 
     ... 
    } 
    public IConnection CreateConnection() { 
     //How would I resolve this? 
     return new Connection(ip, fromPort++); 
    } 
} 

Ahora, el uso:

//Register 
builder.RegisterType<Connection>().As<IConnection>(); 
builder.RegisterType<ConnectionFactory>().As<IConnectionFactory>().SingleInstance(); 
... 

var connection = container.Resolve<IConnectionFactory>(
     new NamedParameter("ip", "127.0.0.1"), 
     new NamedParameter("fromPort", 80).CreateConnection()); 
+0

Quizás desee aclarar su pregunta/problema real con el código anterior o si está buscando enlaces/muestras de documentación para un marco de trabajo de IoC específico. – Reddog

+0

Gracias por el comentario, ¡he tratado de ser más específico! – Larsbj

+0

Me gustaría continuar con la inyección de propiedad y primero resolver el obect y luego pasar las propiedades. – sajoshi

Respuesta

6

una alternativa para pasar los argumentos de constructor en la resolución de tiempo es para codificar esos argumentos en la función de registro:

builder 
.Register(c => new ConnectionFactory("127.0.0.1", 80)) 
.As<IConnectionFactory>() 
.SingleInstance(); 

Autofac utilizará esa función cada vez que necesita para crear la instancia fábrica de conexiones.

Desde que configuramos ConnectionFactory como SingleInstance, se compartirá entre todos los componentes que dependen de IConnectionFactory. Esto significa ConnectionFactory necesidades para mantener su propio estado entre llamadas a CreateConnection:

public class ConnectionFactory : IConnectionFactory 
{ 
    private int _fromPort; 

    public ConnectionFactory(string ip, int fromPort) 
    { 
     ... 
     _fromPort = fromPort; 
    } 

    public IConnection CreateConnection() 
    { 
     return new Connection(ip, _fromPort++); 
    } 
} 

Si tiene una sola vez ConnectionFactory la que, por ejemplo, utiliza una IP diferente, se puede utilizar un registro de llamada:

builder 
.Register(c => new ConnectionFactory("192.168.0.1", 80)) 
.Named<IConnectionFactory>("AlernateConnectionFactory") 
.SingleInstance(); 

Cuando se desea un componente de utilizar esa fábrica en particular en lugar de la opción por defecto, puede utilizar la ResolveNamed method:

builder.Register(c => new Foo(c.ResolvedNamed<IConnectionFactory>("AlernateConnectionFactory"))); 

Esta es una técnica útil para configurar un tipo de múltiples formas y usarlas en lugares específicos.

+0

No puedo creer que no haya pensado en registrar una instancia en lugar de la clase, el concepto es tan simple y justo lo que necesito. * golpea la frente * ¡Gracias! – Larsbj

+0

¿y si los parámetros no son constantes? – sebas

+0

@sebas: Generalmente organizo este tipo de registros en módulos. Los módulos aceptan parámetros de configuración como URL y puertos en sus constructores y los utilizan en los registros. Vea esta respuesta mía para el enfoque específico: http://stackoverflow.com/questions/3587380/dependency-injection-and-appsettings/3592370#3592370 –

2

yo no tengo experiencia con Autofac pero he resuelto un problema muy similar en la Unidad. He aquí un fragmento:

Cuando configuro mi contenedor que hago algo como esto (esto se puede hacer incluso en el archivo de configuración):

string connectionString = ConfigurationManager.ConnectionStrings["XYZ"].ConnectionString; 
Container.RegisterType<IConnection, Connection>(new PerThreadLifetimeManager(), 
               new InjectionConstructor(connectionString)); 

Más tarde, puedo construir las conexiones con sólo decir:

IConnection myConnection = Container.Resolve<IConnection>(); 

o especificar una propiedad de dependencia:

[Dependency] 
IConnection Connection {get;set;} 

o como un parámetro inyectable para la inyección de constructor:

[InjectionConstructor] 
public SomeClassThatUsesConnections(IConnection connection) 
{ ... } 

me dejó la PerThreadLifetimeManager señalar que dejo que el COI se encargue de asegurar que no hay dos hilos están compartiendo una conexión.

Aunque la diferencia con su muestra en la pregunta es sutil, elimina los parámetros de cada instanciación que le permite tenerlo como una propiedad de dependencia o como parte de un constructor de inyección.

Espero que ayude.

+0

Gracias por su respuesta, otra gran idea. No estaba pensando en ese enfoque en absoluto. – Larsbj

1

Un enfoque flexible podría ser crear una "AppConfigConnectionFactory" (o WebConfig, DBConfig, etc ...) y externalizar estas propiedades a través de la configuración. Nunca me he sentido bien cargando datos de configuración directamente desde el marco DI.

+0

¡Gran idea, gracias! – Larsbj

Cuestiones relacionadas