c# - injection - Busque la raíz de composición correcta para una biblioteca.NET
di dependency injection (1)
He leído varias otras preguntas aquí sobre el argumento, más notablemente
Dependency Inject (DI) biblioteca "amigable"
y este artículo (y otro material diverso).
Sin embargo, no tengo claro dónde ubicar la raíz de composición en el proyecto .NET de la biblioteca (DLL). El proyecto no pertenece a ningún tipo específico mencionado en el artículo. En el escritorio, la consola o incluso la aplicación web, este punto está claramente definido.
Mi enfoque actual es envolver el contenedor, registrar tipos y volver a exponer el método Resolve:
class DefaultBootstrapper : IBootstrapper {
public Bootstrapper() {
_container = new XXXContainer();
RegisterTypes(_container);
}
public T Resolve<T>() where T : class {
return _container.Resolve<T>();
}
// + other _container.Resolve() overloads
private readonly XXXContainer _container;
}
Luego impido que los usuarios de la biblioteca creen instancias de raíz de la biblioteca (por ejemplo, definiendo constructores internos) y, por lo tanto, forzando el uso de una fábrica de singleton:
class XYZFactory {
static XYZFactory() {}
private XYZFactory(IBootstrapper bootstrapper) {
_bootstrapper = bootstrapper;
}
public static XYZFactory Instance {
get { return Singleton; }
}
public ABCType CreateABCType(string param1) {
return _bootstrapper.Resolve<ABCType>(param1, _bootstrapper.Resolve<Dependency1>);
}
private static readonly XYZFactory Singleton = XYZFactory(new DefaultBootstrapper);
private readonly IBootstrapper _bootstrapper;
}
La pregunta es, ¿hay un mejor enfoque o un mejor patrón para emplear para ubicar la raíz de composición en un proyecto de biblioteca?
Depende del tipo de biblioteca que está creando. ¿Es su proyecto de biblioteca parte de su propia solución, o es una biblioteca reutilizable de la que otros desarrolladores dependen fuera de su equipo, departamento o incluso de su organización?
En el caso de que sea solo un proyecto de biblioteca parte de una solución, el proyecto de la biblioteca en sí no debería contener una raíz de composición. Por definición, la raíz de la composición es una "ubicación (preferiblemente) única en una aplicación donde los módulos se componen juntos". En otras palabras, su solución tendría uno o varios proyectos de inicio (como una aplicación MVC, servicio WCF, aplicación de consola), y cada proyecto de inicio obtendría su propia raíz de composición. Las capas siguientes no obtendrán su propia raíz de composición.
Esto, por cierto, no significa que no deba evitar la duplicación de código dentro de las raíces de la composición. Cuando hay una gran cantidad de duplicaciones causadas por un cableado predeterminado para los proyectos incluidos (como DAL y BLL), normalmente debe extraer esta lógica a otro proyecto. Puede hacer esto al incluir parte de la lógica de registro dentro de uno de los proyectos (muy probablemente el BLL) y dejar que cada raíz de composición llame a esa lógica compartida, o puede hacerlo agregando un proyecto especial de "arranque" para ese proyecto y los proyectos referenciados. Este proyecto bootstrapper solo contendrá la lógica de registro. Al separar esta lógica de los ensamblados de la aplicación, evita que dichos ensamblajes necesiten una dependencia en la biblioteca de inyección de dependencias utilizada. Sin embargo, generalmente no es un problema si un ensamblado toma una dependencia de dicha biblioteca, siempre y cuando se asegure de que la lógica de la aplicación no tome dependencias del contenedor.
Para las bibliotecas reutilizables, las cosas suelen ser diferentes. En ese caso, los consumidores utilizarán su biblioteca, pero usted no tiene control sobre cómo estructuran su aplicación. A menudo desea suministrar la biblioteca de manera que los consumidores la puedan consumir directamente, sin tener que hacer todo tipo de registros "complejos" en su raíz de composición. A menudo ni siquiera sabes si tienen una raíz de composición en absoluto.
En ese caso, normalmente debería hacer que su biblioteca funcione sin un contenedor DI. Usted no debería tomar una dependencia de dicho contenedor, porque esto arrastraría el contenedor. Si usa un contenedor, pregúntese por qué su biblioteca reutilizable usa un contenedor, y si tiene que ser así. Tal vez lo haga porque diseñó todos los tipos en torno al principio de inyección de dependencia; porque esto hace que las pruebas sean más fáciles. No olvide que este es su problema, no el problema de sus consumidores. Como diseñador de biblioteca reutilizable, debe esforzarse en hacer que su biblioteca sea lo más utilizable posible para sus consumidores. Nunca suponga que sus consumidores están usando un Contenedor DI. Incluso si practican la Inyección de Dependencia, pueden aplicar Pure DI en lugar de un DI Container.
En caso de que esté creando una biblioteca reutilizable, eche un vistazo a esta publicación de blog de Mark Seemann.