dependency-injection - inyección - qué es inversión de control ioc
Ioc/DI-¿Por qué tengo que hacer referencia a todas las capas/conjuntos en la aplicación de entrada? (4)
(En relación con esta pregunta, EF4: ¿Por qué la creación del proxy debe estar habilitada cuando la carga diferida está habilitada? ).
Soy nuevo en DI, así que tengan paciencia conmigo. Entiendo que el contenedor está a cargo de crear instancias de todos mis tipos registrados, pero para ello se requiere una referencia a todos los archivos DLL en mi solución y sus referencias.
Si no estuviera usando un contenedor DI, no tendría que hacer referencia a la biblioteca EntityFramework en mi aplicación MVC3, solo mi capa de negocios, que haría referencia a mi capa DAL / Repo.
Sé que al final del día, todas las DLL están incluidas en la carpeta bin, pero mi problema es tener que hacer referencia explícitamente a través de "agregar referencia" en VS para poder publicar un WAP con todos los archivos necesarios.
Si no estuviera usando un contenedor DI, no tendría que hacer referencia a la biblioteca EntityFramework en mi aplicación MVC3
Incluso cuando utiliza un contenedor DI, no tiene que dejar que su proyecto MVC3 haga referencia a EF, pero (implícitamente) opta por hacerlo implementando Composition Root (la ruta de inicio en la que compone sus gráficos de objeto) dentro de su proyecto MVC3. Si eres muy estricto con respecto a la protección de los límites arquitectónicos mediante ensamblajes, puedes mover tus elementos de presentación Composition Root o your (MVC) a una biblioteca de clases.
En la primera opción, permite que su proyecto MVC3 haga referencia a este ensamblaje separado de ''arranque automático'', y hará referencia a todos los demás ensambles en su solución, además de hacer referencia a su biblioteca de contenedor DI. El problema con esto es que este proyecto de arranque no puede hacer referencia a los tipos ubicados en el proyecto MVC3 (porque provocará una dependencia de ensamblado cíclico). Estos tipos tienen que ser movidos al proyecto bootstrapper (que posiblemente necesite referenciar System.Web.Mvc), o usted necesita mantener una pequeña parte de la configuración del contenedor dentro de su aplicación MVC3. También tenga en cuenta que su proyecto MVC todavía hace referencia indirectamente a todos los demás ensamblados a través del nuevo ensamblaje de arranque, porque las dependencias de ensamblaje son transitivas.
Aunque colocar Composition Root en un ensamblaje separado es algo válido, la mayoría de DI Purist (incluyéndome a mí) generalmente solo mueve la raíz de composición a una biblioteca de clase cuando hay múltiples aplicaciones finales (es decir, una aplicación web + servicio web + servicio de Windows ) que utilizan la misma capa de negocios. Cuando tengo una sola aplicación, mantengo la raíz de composición dentro de mi aplicación final.
La segunda opción es mover todas las clases relacionadas con MVC (vistas, controladores, etc.) desde el proyecto de inicio a una biblioteca de clases. Esto permite que este nuevo conjunto de capa de presentación permanezca desconectado del resto de la aplicación. Su proyecto de aplicación web se convertirá en un shell muy delgado con la lógica de inicio requerida. El proyecto de aplicación web será la raíz de composición que hace referencia a todos los demás ensamblajes.
Extraer la lógica de presentación a una biblioteca de clases puede complicar las cosas al trabajar con MVC. Será más difícil conectar todo, ya que los controladores y vistas, imágenes, archivos css, etc. no están en el proyecto de inicio. Esto es probablemente factible, pero llevará más tiempo configurarlo.
Ambas opciones tienen sus inconvenientes y es por eso que, en general, les aconsejo que mantengan la Raíz de composición en el proyecto web. Muchos desarrolladores no quieren que su ensamblaje MVC dependa del ensamblaje DAL, pero eso no es realmente un problema. No olvide que los ensamblados son un artefacto de implementación ; divide el código en varios conjuntos para permitir que el código se implemente por separado. Una capa arquitectónica, por otro lado, es un artefacto lógico . Es muy posible (y común) tener múltiples capas en el mismo conjunto. En este caso, tendremos la raíz de composición (capa) y la capa de presentación en el mismo proyecto de aplicación web (por lo tanto, en el mismo ensamblaje). Y a pesar de que ese conjunto hace referencia al ensamblaje que contiene el DAL, la Capa de presentación aún no hace referencia a la Capa de acceso a datos . Esta es una gran distinción. Por supuesto, cuando hacemos esto, perdemos la capacidad del compilador para verificar esta regla de arquitectura en tiempo de compilación, pero esto no debería ser un problema. La mayoría de las reglas arquitectónicas en realidad no pueden ser verificadas por el compilador y siempre hay algo como el sentido común. Y si no hay sentido común en su equipo, siempre puede usar revisiones de código (que cada equipo debe hacer siempre por IMO). También puede usar una herramienta como NDepend (que es comercial), que le ayuda a verificar sus reglas arquitectónicas. Cuando integra NDepend con su proceso de compilación, puede advertirle cuando alguien revisó el código que infringe dicha regla de arquitectura.
Si no estuviera usando un contenedor DI, no tendría que hacer referencia a la biblioteca EntityFramework en mi aplicación MVC3, solo mi capa comercial que haría referencia a mi capa DAL / Repo.
Sí, esa es exactamente la situación que DI trabaja tan duro para evitar :)
Con un código estrechamente acoplado, cada biblioteca puede tener solo algunas referencias, pero estas tienen otras referencias, creando un gráfico profundo de dependencias, como este:
Como el gráfico de dependencia es profundo, significa que la mayoría de las bibliotecas arrastran muchas otras dependencias, por ejemplo, en el diagrama, la Biblioteca C se arrastra a lo largo de la Biblioteca H, Biblioteca E, Biblioteca J, Biblioteca M, Biblioteca K y Biblioteca N. Esto hace que sea más difícil reutilizar cada biblioteca independientemente del resto, por ejemplo, en pruebas unitarias .
Sin embargo, en una aplicación débilmente acoplada, moviendo todas las referencias a la Raíz de Composición , el gráfico de dependencia está severamente aplanado :
Como se ilustra con el color verde, ahora es posible reutilizar la Biblioteca C sin arrastrar las dependencias no deseadas.
Sin embargo, dicho todo esto, con muchos Contenedores DI, no es necesario agregar referencias duras a todas las bibliotecas requeridas. En su lugar, puede usar el enlace diferido en forma de escaneo de ensamblaje basado en convenciones (preferido) o configuración XML.
Sin embargo, cuando haga eso, debe recordar copiar los ensamblajes a la carpeta bin de la aplicación, porque eso ya no ocurre automáticamente. Personalmente, rara vez encuentro que valga la pena ese esfuerzo extra.
Si no estuviera usando un contenedor DI, no tendría que hacer referencia a la biblioteca EntityFramework en mi aplicación MVC3, solo mi capa de negocios que haría referencia a mi capa DAL / Repo.
Puede crear un proyecto separado llamado "DependencyResolver". En este proyecto, debe hacer referencia a todas sus bibliotecas.
Ahora, la capa de interfaz de usuario no necesita NHibernate / EF ni ninguna otra biblioteca que no sea relevante para la interfaz de usuario excepto la de Castle Windsor a la que se hará referencia.
Si quieres ocultar Castle Windsor y DependencyResolver desde tu capa de interfaz de usuario, puedes escribir un HttpModule que llame al registro de IoC.
Solo tengo un ejemplo para StructureMap:
public class DependencyRegistrarModule : IHttpModule
{
private static bool _dependenciesRegistered;
private static readonly object Lock = new object();
public void Init(HttpApplication context)
{
context.BeginRequest += (sender, args) => EnsureDependenciesRegistered();
}
public void Dispose() { }
private static void EnsureDependenciesRegistered()
{
if (!_dependenciesRegistered)
{
lock (Lock)
{
if (!_dependenciesRegistered)
{
ObjectFactory.ResetDefaults();
// Register all you dependencies here
ObjectFactory.Initialize(x => x.AddRegistry(new DependencyRegistry()));
new InitiailizeDefaultFactories().Configure();
_dependenciesRegistered = true;
}
}
}
}
}
public class InitiailizeDefaultFactories
{
public void Configure()
{
StructureMapControllerFactory.GetController = type => ObjectFactory.GetInstance(type);
...
}
}
DefaultControllerFactory no utiliza el contenedor de IoC directamente, pero delega en los métodos de contenedor de IoC.
public class StructureMapControllerFactory : DefaultControllerFactory
{
public static Func<Type, object> GetController = type =>
{
throw new InvalidOperationException("The dependency callback for the StructureMapControllerFactory is not configured!");
};
protected override IController GetControllerInstance(RequestContext requestContext, Type controllerType)
{
if (controllerType == null)
{
return base.GetControllerInstance(requestContext, controllerType);
}
return GetController(controllerType) as Controller;
}
}
El delegado de GetController
se establece en un Registro de StructureMap (en Windsor debe ser un instalador).
+ Hay una dependencia: si un objeto crea una instancia de otro objeto. + No hay dependencia: si un objeto espera una abstracción (inyección de contructor, inyección de método ...)
+ Las referencias de ensamblaje (haciendo referencia a dll, servicios web ...) son independientes del concepto de dependencia, porque para resolver una abstracción y poder compilar el código, la capa debe hacer referencia a él.