6

Tengo un servicio de WCF y en el cliente que tengo:La inyección de dependencia con múltiples repositorios

var service = new ServiceReference1.CACSServiceClient() 

El código de servicio actual es:

public CACSService() : this(new UserRepository(), new BusinessRepository()) { } 

public CACSService(IUserRepository Repository, IBusinessRepository businessRepository) 
{ 
    _IRepository = Repository; 
    _IBusinessRepository = businessRepository; 
} 

lo tanto, todo esto funciona bien, pero yo don Me gusta cómo estoy actualizando todos los repositorios al mismo tiempo porque el código del cliente puede no necesitar actualizar el UserRepository y solo está interesado en actualizar el BusinessRepository. Entonces, ¿hay alguna manera de pasarle algo a este código:
var service = new ServiceReference1.CACSServiceClient()
para decir qué repositorio a nuevo según el código que está llamando al servicio o cualquier otra sugerencia que necesite cuando diseñe los repositorios para el marco de mi entidad. Thankx

+1

+1 para "actualizar" – Jacob

Respuesta

0

En lugar de crear instancias ("renovar") los repositorios en construcción, puede cargarlos de forma perezosa en sus propiedades. Esto te permitiría mantener tu segundo constructor, pero que tu primer constructor no haga nada.

El usuario podría asignar estos, según sea necesario, de lo contrario.

Por ejemplo:

public class CACSService 
{ 
    public CACSService() {} 

    public CACSService(IUserRepository Repository, IBusinessRepository businessRepository) 
    { 
     _IRepository = Repository; 
     _IBusinessRepository = businessRepository; 
    } 

    private IUserRepository _IRepository; 
    public IUserRepository Repository 
    { 
     get { 
      if (this._IRepository == null) 
        this._IRepository = new UserRepository(); 
      return this._IRepository; 
     } 
    } 

    // Add same for IBusinessRepository 
} 
0

hacer sus repositorios tienen estado a nivel de objeto? Probablemente no, así que créelos como singletons y tenga un contenedor DI para proporcionarlos a CACService.

De lo contrario, ¿son realmente caros de crear? De lo contrario, la creación de uno nuevo por solicitud tiene un costo insignificante en comparación con las operaciones de base de datos y RPC.

Al usar el contenedor de inyección de dependencia Ninject, su CACService podría tener el siguiente aspecto. Otros contenedores DI tienen mecanismos igualmente concisos de hacer esto.

public class CACSService 
{ 
    public CACService 
    { 
     // need to do this since WCF creates us 
     KernelContainer.Inject(this); 
    } 

    [Inject] 
    public IUserRepository Repository 
    { set; get; } 

    [Inject] 
    public IBusinessRepository BusinessRepository 
    { set; get; } 
} 

Y durante el inicio de su aplicación, le diría a Ninject acerca de estos tipos.

Bind<IUserRepository>().To<UserRepository>().InSingletonScope(); 
Bind<IBusinessRepository>().To<BusinessRepository>().InSingletonScope(); 
+3

No es necesario recurrir a Singletons y constructores predeterminados. WCF es perfectamente compatible con ** Constructor Injection **. –

+0

Esta implementación suena bien, le daré una oportunidad y también probaré lo que dijo Mark Seeman sobre la carga lenta del repositorio. – user282807

+0

Los amigos no permiten que los amigos escriban singletons. –

0

Prefacio: Esta es una guía general para la dependencia de inversión. Si necesita que el constructor predeterminado haga el trabajo (por ejemplo, si se actualiza mediante reflexión o algo más), será más difícil hacerlo limpiamente.

Si desea que su aplicación sea configurable, significa que puede variar cómo se construye su gráfico de objetos. En términos muy simples, si desea variar una implementación de algo (por ejemplo, algunas veces quiere una instancia de UserRepository, otras veces quiere una instancia de MemoryUserRepository), entonces el tipo que usa la implementación (CACService en este caso) debería No se le cobrará por renovarlo. Cada uso de new lo vincula a una implementación específica. Misko has written some nice articles about this point.

El principio de inversión de dependencia a menudo se denomina "parametrizar desde arriba", ya que cada tipo concreto recibe sus dependencias (ya instanciadas) de la persona que llama.

Para poner esto en práctica, mueva el código de creación de objeto fuera del constructor sin parámetros de CACService y colóquelo de fábrica.

continuación, puede elegir a cablear las cosas de manera diferente en base a cosas como:

  • lectura en un archivo de configuración
  • pasando argumentos a la fábrica
  • crear un tipo diferente de fábrica

Separación de tipos en dos categorías (tipos que crean cosas y tipos que hacen cosas) es una técnica poderosa.

E.g. Aquí hay una manera relativamente simple de hacerlo usando una interfaz de fábrica: simplemente reactivamos la fábrica que sea apropiada para nuestras necesidades y llamamos al método Create. Usamos un contenedor de Inyección de Dependencia (Autofac) para hacer esto en el trabajo, pero puede ser excesivo para sus necesidades.

public interface ICACServiceFactory 
{ 
    CACService Create(); 
} 

// A factory responsible for creating a 'real' version 
public class RemoteCACServiceFactory : ICACServiceFactory 
{ 
    public CACService Create() 
    { 
     return new CACService(new UserRepository(), new BusinessRepository()); 
    }   
} 

// Returns a service configuration for local runs & unit testing 
public class LocalCACServiceFactory : ICACServiceFactory 
{ 
    public CACService Create() 
    { 
     return new CACService(
       new MemoryUserRepository(), 
       new MemoryBusinessRepository()); 
    }  
} 
16

La belleza de pura DI es que usted no debe preocuparse por las vidas de sus dependencias, porque éstos son gestionados por usted por quien suministrarlos (un contenedor de DI, o algún otro código que escribió a sí mismo)

(Dicho sea de paso, que debe deshacerse de sus actuales Bastard inyección constructores. Bote el constructor sin parámetros y mantener el que anuncia explícitamente sus dependencias.)

Mantenga su constructor como este, y el uso _IRepository y _IBusinessRepository según sea necesario:

public CACSService(IUserRepository Repository, IBusinessRepository businessRepository) 
{ 
    _IRepository = Repository; 
    _IBusinessRepository = businessRepository; 
} 

Si usted se preocupa de que uno de estos repositorios no van a ser necesarios en tiempo de ejecución, se puede inyectar una aplicación perezoso de carga de, por ejemplo, IUserRepsository en lugar de la real originalmente tenías en mente.

Asumamos que IUserRepository se ve así:

public interface IUserRepository 
{ 
    IUser SelectUser(int userId); 
} 

Ahora puede implementar una aplicación perezoso de carga así:

public class LazyUserRepository : IUserRepository 
{ 
    private IUserRepository uRep; 

    public IUser SelectUser(int userId) 
    { 
     if (this.uRep == null) 
     { 
      this.uRep = new UserRepository(); 
     } 
     return this.uRep.SelectUser(userId); 
    } 
} 

Al crear CACService, puede hacerlo mediante la inyección de LazyUserRepository en él, lo que garantiza que el UserRepository real solo se inicialice si es necesario.

La belleza de este enfoque es que no tiene que hacer esto hasta que lo necesite. A menudo, esto realmente no será necesario, por lo que es bueno posponer tales optimizaciones hasta que realmente sean necesarias.

Primero describí la técnica de Lazy Dependencieshere y here.

+2

de acuerdo. No se limite a usar el Ctor por defecto porque eso es lo que sugiere WCF. use IInstanceProvider para construir su instancia de servicio. –

+0

Thankx Mark para la respuesta. Podría tener 10 o 20 repositorios para mis clases de dominio, ¿tengo que implementar la carga diferida para cada uno? eso sería mucho código. – user282807

+0

Bueno, uno de mis puntos principales es que quizás no tengas que hacer esto en absoluto. Considere cuidadosamente si esto podría ser una optimización prematura o no. Como ejemplo, si usa LINQ to SQL o LINQ to Entities, es muy posible que termine implementando todos sus repositorios basados ​​en el mismo contexto, y en tal caso, la sobrecarga de crear varias instancias de repositorio puede ser insignificante. –

Cuestiones relacionadas