En general, la mayoría de las dependencias se pueden inyectar en su clase en el momento de su creación. Sin embargo, en este caso particular, necesita un componente que debe crearse bajo demanda en el momento del uso. En tales casos, es muy difícil eliminar por completo la dependencia de un contenedor IoC. Mi enfoque siempre ha sido crear una fábrica que se inyecte en la clase en el momento de la creación, que a su vez encapsula todo el uso directo de la IoC. Esto permite a sus fábricas, para burlarse de las pruebas, en lugar del contenedor de IoC sí ... que tiende a ser mucho más fácil:
// In Presentation.csproj
class PresentationController
{
public PresentationController(IDataContextFactory dataContextFactory, IRepositoryFactory repositoryFactory)
{
#region .NET 4 Contract
Contract.Requires(dataContextFactory != null);
Contract.Requires(repositoryFactory != null);
#endregion
_dataContextFactory = dataContextFactory;
_repositoryFactory = repositoryFactory;
}
private readonly IDataContextFactory _dataContextFactory;
private readonly IRepositoryFactory _repositoryFactory;
public void Action()
{
using (IDataContext dc = _dataContextFactory.CreateInstance())
{
var repo = _repositoryFactory.CreateUserRepository();
// do stuff with repo...
}
}
}
// In Factories.API.csproj
interface IDataContextFactory
{
IDataContext CreateInstance();
}
interface IRepositoryFactory
{
IUserRepository CreateUserRepository();
IAddressRepository CreateAddressRepository();
// etc.
}
// In Factories.Impl.csproj
class DataContextFactory: IDataContextFactory
{
public IDataContext CreateInstance()
{
var context = IoC.Resolve<IDataContext>();
// Do any common setup or initialization that may be required on 'context'
return context;
}
}
class RepositoryFactory: IRepositoryFactory
{
public IUserRepository CreateUserRepository()
{
var repo = IoC.Resolve<IUserRepository>();
// Do any common setup or initialization that may be required on 'repo'
return repo;
}
public IAddressRepository CreateAddressRepository()
{
var repo = IoC.Resolve<IAddressRepository>();
// Do any common setup or initialization that may be required on 'repo'
return repo;
}
// etc.
}
La ventaja de este enfoque es que, mientras que no se puede eliminar por completo la dependencia de la COI en sí mismo, puede encapsularlo en un único tipo de objeto (una fábrica), desacoplando la mayor parte de su código del contenedor IoC. Esto mejora la agilidad de los códigos a la luz de, por ejemplo, el cambio de un contenedor de IoC a otro (es decir, Windsor a Ninject).
Cabe señalar, una consecuencia interesante de esto, es que sus fábricas generalmente se inyectan a sus dependientes por el mismo marco de IoC que utilizan. Si está utilizando Castle Windsor, por ejemplo, crearía una configuración que le diga al contenedor IoC que inyecte las dos fábricas en su componente comercial cuando se cree. El componente comercial en sí mismo también puede tener una fábrica ... o, simplemente, puede ser inyectado por el mismo marco de trabajo de IoC en un componente de nivel superior, etc., etc., ad inf.
Gracias por la respuesta. El único problema es que el IoC que estoy usando debe tener un alcance relativo a una instrucción 'using'. Luego, si resuelvo, diga 'IDataContext' y se resolverá la * instancia única * para ese ámbito particular. No quiero que mis controladores, etc., estén al tanto de un contenedor IoC, pero ¿hay realmente alguna forma de evitarlo? – TheCloudlessSky
Lo que me pregunto es si un Controlador debería ser capaz de llamar a IoC.Resolve? Si no, ¿quién debería hacer esta llamada? –
TheCloudlessSky
¿Podría explicar un poco más sobre este alcance? ¿Qué contenedor de IoC estás usando? En términos generales, acoplar cualquiera de sus códigos al marco del contenedor de cualquier manera es un tipo negativo de acoplamiento ... debe evitarlo a toda costa. En mi experiencia, rara vez, o nunca, se requiere un alcance (o contexto) para que funcione un contenedor IoC. Si funciona de esa manera, encontraría un contenedor alternativo o encontraría una forma de proporcionar ese contexto a las fábricas que resuelvan sus objetos y mantendrán su estructura de IoC desacoplada tanto como sea posible. – jrista