2012-01-06 18 views
18

¿Cómo procedería para registrar diferentes instancias de IDbConnectionFactory en Funq y luego acceder a ellas directamente en sus servicios? ¿Las instancias nombradas de alguna manera entran en juego aquí?Cómo registrar varias instancias de IDbConnectionFactory utilizando Funq en ServiceStack.net

¿Es este el mejor enfoque para usar al usar diferentes bases de datos entre servicios?

Gracias!

EDIT:

Un ejemplo;). Podría estar lejos de aquí porque soy bastante nuevo en IoC, pero digo, por ejemplo, que tengo dos conexiones de bases de datos separadas que me gustaría inyectar. En ServiceStack, esto se hace en Global.asax.

container.Register<IDbConnectionFactory>(c => 
      new OrmLiteConnectionFactory(@"Connection String 1", SqlServerOrmLiteDialectProvider.Instance));            

container.Register<IDbConnectionFactory>(c => 
      new OrmLiteConnectionFactory(@"Connection String 2", SqlServerOrmLiteDialectProvider.Instance));     

Ambos parecen inyectarse honky dory.

Estos se accede de forma automática en el extremo servicio a través de algo como esto:

public IDbConnectionFactory DbFactory { get; set; } 

En este caso, me parece estar dando el primero registrado. ¿Cómo puedo acceder a uno específico al final del servicio? Con suerte eso lo hace un poco más claro.

Aquí está un ejemplo de pleno derecho de ServiceStack.Examples que sólo utiliza 1 IDbConnectionFactory: Movies Rest

+0

¿Puede mostrar algún código? Creo que podemos darle algunos consejos sobre el diseño de su aplicación, pero para esto, necesitamos más información sobre el diseño real. Sería interesante ver en qué servicios se inyectan esas aplicaciones 'IDbConnectionFactory', y qué hacen esos servicios con esas dependencias' IDbConnectionFactory'. – Steven

+0

Sin embargo, tenga en cuenta que Funq es un contenedor de IoC muy simplista (algunos incluso podrían argumentar que no es un contenedor de IoC), y todo debe estar cableado a mano. Sin embargo, puede inyectar todo lo que desee en cada servicio que cree. – Steven

+0

Actualicé la pregunta, lo que es un poco más claro y encontré tu artículo sobre Simple Injector. Estoy dando una lectura ahora con la esperanza de profundizar mi comprensión de IoC. –

Respuesta

14

Mi pregunta anterior sigue siendo válida, pero lo siguiente podría ayudar a usted de todos modos.

Funq no es compatible con la inyección automática del constructor (cableado automático a.k.a.), y tendrá que hacer esto a mano construyendo Func<T> expresiones lambda. Como ya está haciendo la inyección de constructor a mano, es fácil elegir qué IDbConnectionFactory desea inyectar en sus servicios. Ejemplo:

IDbConnectionFactory yellowDbConFactory = 
    new YellowDbConnectionFactory(); 

IDbConnectionFactory blueDbConFactory = 
    new BlueDbConnectionFactory(); 

IDbConnectionFactory purpleDbConFactory = 
    new PurpleDbConnectionFactory(); 

container.Register<IService1>(c => 
    new Service1Impl(yellowDbConFactory, 
     c.Resolve<IDep1>()); 

container.Register<IService2>(c => 
    new Service2Impl(blueDbConFactory); 

container.Register<IService3>(c => 
    new Service3Impl(purpleDbConFactory, 
     c.Resolve<IDep2>()); 

Por supuesto, también se puede utilizar el nombre registros, así:

container.Register<IDbConnectionFactory>("yellow", 
    new YellowDbConnectionFactory()); 

container.Register<IDbConnectionFactory>("blue", 
    new BlueDbConnectionFactory()); 

container.Register<IDbConnectionFactory>("purple", 
    new PurpleDbConnectionFactory()); 

container.Register<IService1>(c => 
    new Service1Impl(
     c.Resolve<IDbConnectionFactory>("yellow"), 
     c.Resolve<IDep1>()); 

container.Register<IService2>(c => 
    new Service2Impl(
     c.Resolve<IDbConnectionFactory>("blue")); 

container.Register<IService3>(c => 
    new Service3Impl(
     c.Resolve<IDbConnectionFactory>("purple"), 
     c.Resolve<IDep2>()); 

Debido a la falta de apoyo para auto-cableado, que va a terminar con estos registros bastante incómodo, y esto muy pronto resultará en una pesadilla de mantenimiento de su raíz de composición, pero eso no está relacionado con su pregunta ;-)

Por lo general, debe tratar de evitar la ambigüedad en su registro. En su caso, tiene una única interfaz, que hace dos cosas (se conecta a dos bases de datos).A menos que ambos comparten la misma base de datos de modelo exacto, cada base de datos se merece su propia interfaz (si las dos implementaciones no son intercambiables, se le violando la Liskov substitution principle):

interface IYellowDbConnectionFactory : IDbConnectionFactory 
{ 
} 

interface IPurpleDbConnectionFactory : IDbConnectionFactory 
{ 
} 

Debido a las obras de manera ServiceStack, es probable que tenga para implementar una aplicación para cada uno:

class YellowDbConnectionFactory : OrmLiteConnectionFactory, 
    IYellowDbConnectionFactory 
{ 
    public YellowDbConnectionFactory(string s) : base(s){} 
} 

class PurpleDbConnectionFactory : OrmLiteConnectionFactory, 
    IPurpleDbConnectionFactory 
{ 
    public YellowDbConnectionFactory(string s) : base(s){} 
} 

Ahora se debe cambiar la definición de sus servicios a utilizar la interfaz específica en lugar de utilizar el IDbConnectionFactory:

public class MovieService : RestServiceBase<Movie> 
{ 
    private readonly IYellowDbConnectionFactory dbFactory; 

    public MovieService(IYellowDbConnectionFactory factory) 
    { 
     this.dbFactory = factory; 
    } 
} 

Tenga en cuenta que esta clase ahora usa inyección de constructor en lugar de inyección de propiedad. Puede hacer que esto funcione con la inyección de propiedad, pero generalmente es mejor usar la inyección de constructor. Aquí hay un SO question al respecto.

Con Funq, la configuración será el siguiente aspecto:

container.Register<MovieService>(c => 
    new MovieService(
     c.Resolve<IYellowDbConnectionFactory>()); 

Esas dos nuevas interfaces y dos clases y el cambio a la MovieService no se gana mucho, porque Funq no soporta auto alambrado. Usted será quien conecte todo junto manualmente. Sin embargo, cuando se cambia a un marco de trabajo que admite para el auto-cableado, este diseño permite al contenedor inyectar las dependencias correctas sin ningún problema, porque no hay discusión sobre qué inyectar.

+1

Gracias por la respuesta completa. Esto es exactamente lo que estaba buscando. –

+5

Nota: ServiceStack realmente admite el cableado automático con su Funq.Container; consulte mi respuesta. – mythz

+1

@Steven ¿Qué sucede si las bases de datos comparten el mismo modelo? es decir, inquilino múltiple –

11

Aunque Funq no es compatible con el cableado automático, la implementación de ServiceStack sí lo hace. La última versión de ServiceStack incluye las sobrecargas Funq.Container:

container.RegisterAutoWired<T>(); 
container.RegisterAutoWiredAs<T,TAs>(); 
container.RegisterAs<T,TAs>(); 

Así en el ejemplo de Steven también se puede hacer:

container.RegisterAs<YellowDbConnectionFactory,IYellowDbConnectionFactory>(); 

Y se registrará automáticamente las dependencias para usted.

+0

Es bastante extraño que una implementación de Service Framework tenga dicha característica. Esto parece una característica para un contenedor IoC, y no para ServiceStack. – Steven

+1

Estoy de acuerdo, publiqué esto hace mucho tiempo en la lista de correo de Funq, pero no salió nada de él http://funq.codeplex.com/workitem/2158 – mythz

+2

El framework Funq parece estar abandonado desde hace mucho tiempo. ¿Por qué no cambia a Simple Injector como marco de IoC predeterminado para ServiceStack? Dado que ServiceStack parece ser un marco de alto rendimiento, Simple Injector es una buena opción, ya que es el marco de IoC más rápido en el campo. Creo que ServiceStack es realmente agradable, por cierto. – Steven

1

Trate de usar el patrón Repositorio en lugar de este IoC (que simplemente complica las cosas innecesariamente). El código anterior parece no funcionar. Sospecho que algo ha cambiado. Todavía no tengo claro cómo registrar un IDbConnectionFactory rellena mágicamente la propiedad IDbConnection. Me encantaría una explicación sobre esto. Si alguna vez alguien hace que esto funcione usando el contenedor ServiceStack IoC ... entonces me encantaría ver cómo. Y sería muy beneficioso actualizar los documentos de SS (estoy bastante contento de hacerlo)

+0

En cuanto a IDbConnectionFactory, puede consultar el código de ServiceStack OrmLite: public virtual IDbConnection Db {get {return this.db ?? (this.db = OrmLiteConnectionFactoryExtensions.Open (this.TryResolve ())); }} – labilbe

3

Pensé que podría aportar 2 centavos aquí, aunque me doy cuenta de que la pregunta es bastante antigua. Yo quería tener acceso a una base de datos transaccional y una base de datos de registro de ServiceStack y así es como terminé haciéndolo desde el AppHostBase Configurar() Método:

  container.Register<IDbConnectionFactory>(
       c => { 
        OrmLiteConnectionFactory dbFactory = new OrmLiteConnectionFactory(ConfigurationManager.ConnectionStrings["MyTransactionalDB"].ConnectionString, MySqlDialect.Provider); 
        dbFactory.ConnectionFilter = x => new ProfiledDbConnection(x, Profiler.Current); 
        dbFactory.RegisterConnection("LoggingDB", ConfigurationManager.ConnectionStrings["MyLoggingDB"].ConnectionString, MySqlDialect.Provider); 

        return dbFactory; 
       }); 

Por defecto, el "MyTransactionalDB" se utiliza al abrir una conexión de fábrica, pero puedo acceder explícitamente a la base de datos de registro desde un servicio a través de:

 using (var db = DbFactory.Open("LoggingDB")) 
     { 
      db.Save(...); 
     } 
Cuestiones relacionadas