2009-12-11 14 views
9

Estoy tratando de descubrir cómo usar IoC en situaciones donde las clases dependientes pueden cambiar en función de alguna variable en la aplicación (en este caso, estado de la sesión). Por ejemplo, cada uno de nuestros clientes tiene una base de datos diferente, por lo que la conexión a la base de datos debe basarse en un valor almacenado en su Sesión (particularmente porque algunos usuarios pueden tener múltiples bases de datos si poseen múltiples negocios y cambiarían de base de datos) .Cómo configurar IoC cuando una clase de clave necesita Sesión (u otra variable específica del contexto)

Aquí es un ejemplo genérico de cómo nos Actualmente configurado esta estructura:

public class MyTestController : ControllerBase 
{ 
    Repository _rep; 

    public MyTest(Repository rep) 
    { 
     _rep = rep; 
    } 

    public MyTest() 
    { 
     string connString = String.Format("Server={0}; Database={1};" 
      , SessionContainer.ServerName, SessionContainer.DatabaseName; 
     var dc = new DataContext(connString); 
     _rep = new Repository(dc); 
    } 

    public int SampleFn() 
    { 
     return _rep.GetCountOfEmployees(); 
    } 
} 

public class Repository 
{ 
    DataContext _context; 

    public Repository(DataContext context) 
    { 
     _context = context; 
    } 
} 

¿Seríamos capaces de hacerlo usando COI y eliminar los predeterminados c-res? ¿Si es así, cómo? No tengo ningún problema solo con usar D.I. así, pero me gustaría explorar la posibilidad de un StructureMap o Unity (nota: normalmente pasamos en db/server a una clase de fábrica que construye el contexto de datos ... el ejemplo de arriba es solo por brevedad).

Respuesta

13

La forma en que se crea la instancia del Repositorio, así como su duración, no afecta al Controlador.

Cuando registra componentes en el contenedor, debe especificar la duración del componente. Dependiendo de su implementación, puede simplemente elegir configurar el tiempo de vida del repositorio para seguir la sesión.

En cualquier caso, podría utilizar una fábrica para crear el repositorio de la sesión, pero haga esto desde fuera del controlador.

Definitivamente debe deshacerse del constructor predeterminado.


De la parte superior de mi cabeza no puedo recordar cómo se hace esto en la Unidad o StructureMap, así que aquí está un ejemplo el castillo de Windsor.

Definir una fábrica Resumen:

public interface IRepositoryFactory 
{ 
    Repository Create(); 
} 

y una implementación

public class MyRepositoryFactory : IRepositoryFactory 
{ 
    private readonly HttpContextBase httpContext; 

    public MyRepositoryFactory(HttpContextBase httpContext) 
    { 
     if (httpContext == null) 
     { 
      throw new ArgumentNullException("httpContext"); 
     } 

     this.httpContext = httpContext; 
    } 

    #region IRepositoryFactory Members 

    public Repository Create() 
    { 
     // return Repository created from this.httpContext 
    } 

    #endregion 
} 

Ahora registrar todas las cosas

container.AddFacility<FactorySupportFacility>(); 
container.Register(Component.For<IRepositoryFactory>() 
    .ImplementedBy<MyRepositoryFactory>() 
    .LifeStyle.PerWebRequest); 
container.Register(Component.For<Repository>() 
    .UsingFactory((IRepositoryFactory f) => f.Create()) 
    .LifeStyle.PerWebRequest); 

Aquí he utilizado el estilo de vida PerWebRequest, pero si desea optimizar puede querer crear un estilo de vida PerWebSession personalizado. Esto no es demasiado difícil de hacer en Castle, pero no puedo recordar lo difícil que es en otros Contenedores DI.

También necesitará registrar HttpContextBase, ya que MyRepositoryFactory depende de ello.

+0

Marca: ¿puede ser más específico o dar un ejemplo? Podríamos tener múltiples objetos de repositorio, todos los cuales necesitarían usar el mismo DataContext (para un procesamiento de transacción adecuado). No tengo problemas para registrar esto en el contenedor IoC cuando "DataContext" usa una cadena de conexión global o definida en el contenedor, pero ¿qué sucede cuando la cadena de conexión está en la sesión del usuario? Siento que me falta algo obvio. –

+0

Agregué un ejemplo a mi respuesta. –

+0

¡Ah, ja, creo que lo entiendo ahora! =) Te volví a votar abajo para poder votarte mañana por la doble victoria. Gran respuesta. –

Cuestiones relacionadas