c# inversion-of-control castle-windsor

c# - Uso de Contenedores de IoC; específicamente Windsor



inversion-of-control castle-windsor (5)

Creo que la respuesta a esta pregunta es tan obvia que nadie se ha molestado en escribir sobre esto, pero es tarde y realmente no puedo entender esto.

He estado leyendo en contenedores IoC (Windsor en este caso) y me falta cómo hablas con el contenedor desde varias partes de tu código.

Obtuve DI, he estado haciendo deficientes a DI (constructores vacíos que llaman a constructores de inyección sobrecargados con implementaciones de parámetros predeterminadas) durante algún tiempo y puedo ver completamente el beneficio del contenedor. Sin embargo, me falta una pieza vital de información; ¿cómo se supone que debes hacer referencia al contenedor cada vez que necesites un servicio de él?

¿Creo un insulto global único que paso por alto? ¡Seguramente no!

Sé que debería llamar esto:

WindsorContainer container = new WindsorContainer(new XmlInterpreter());

(por ejemplo) cuando quiero cargar mi configuración XML, pero ¿qué hago con el contenedor? ¿La creación de un nuevo contenedor cada vez que persiste la configuración cargada a través de algunos majicks estáticos internos o de lo contrario, o tengo que volver a cargar la configuración cada vez (supongo que no, o lifecycles couldnt).

El hecho de no entender esto me impide saber cómo funcionan los ciclos de vida y seguir usando algo de la calidad del conocimiento de la vida.

Gracias,

Andrés


Estoy usando una implementación de esta interfaz:

public interface IResolver { object Resolve(Type type); object Resolve(string name); T Resolve<T>() where T : class; T Resolve<T>(string name) where T : class; }

Que en realidad está envuelto en una clase estática global, por ejemplo:

public static class Resolver // : IResolver { private static IResolver _current; public static object Resolve(Type type) { return Current.Resolve(type); } public static object Resolve(string name) { return Current.Resolve(name); } public static T Resolve<T>() where T : class { return Current.Resolve<T>(); } public static T Resolve<T>(string name) where T : class { return Current.Resolve<T>(name); } private static IResolver Current { get { if (_current == null) { _current = new SpringResolver(); } return _current; } } }

También estoy tratando de seguir la regla simple: use la clase Resolver como menos posible, en su lugar, inyecte servicios en objetos que necesitan esos servicios.



Como las otras respuestas aquí indican que hay muchas opciones, y nuevamente nos quedamos a nosotros mismos para descubrir qué es lo mejor en nuestro caso.

Dicho esto, la OMI que tiene un contenedor global al que se accede a través de su aplicación de alguna manera rompe el aislamiento ya que una gran cantidad de código ahora depende de la clase global. Además, para las aplicaciones que se dividen en varios ensamblados, el contenedor global debe estar disponible para todos estos ensamblajes.

Con Unity puedes tener un parámetro IUnityContainer en tu constructor y el contenedor se inyectará automáticamente en la instancia cuando resuelvas la clase. De esta forma, para los servicios que necesitan resolver otros servicios, los transfiere en el contenedor en lugar de forzar a la clase a hacer referencia a la clase externa.

No estoy seguro de cómo otros marcos soportan este escenario (Windsor inyectará IKernel ).


En general, desea mantener solo una instancia durante toda la vida de toda la aplicación. Lo que hago la mayoría del tiempo es inicializar el contenedor cuando se inicia la aplicación, y luego uso las fábricas tipeadas para extraer objetos sin conocimiento del contenedor.

Otro enfoque popular es envolver la instancia del contenedor con la clase estática y usar esa clase estática para acceder a su contenedor (singleton). Puede encontrar un ejemplo de eso en la biblioteca Rhino.Commons de Ayende aquí . Sin embargo, este enfoque tiene graves inconvenientes y debe evitarse.


El 99% de los casos es una instancia de contenedor por aplicación. Normalmente lo inicializa en Application_Start (para una aplicación web), así .

Después de eso, depende realmente del consumidor del contenedor. Por ejemplo, algunos frameworks, como Monorail y ASP.NET MVC le permiten interceptar la creación de las instancias (los controladores en este caso), así que solo registra los controladores y sus dependencias en el contenedor y eso es todo, siempre que obtenga un solicitar que el contenedor se encargue de inyectar a cada controlador sus dependencias. Ver por ejemplo este controlador ASP.NET MVC . En estos marcos, casi nunca necesita llamar o incluso hacer referencia al contenedor en sus clases, que es el uso recomendado.

Otros frameworks no le permiten ingresar fácilmente al proceso de creación (como Webforms) por lo que debe recurrir a hacks como este , o extraer las dependencias requeridas (es decir, llamar explícitamente al contenedor). Para extraer dependencias, use una puerta de enlace estática al contenedor como este o el descrito por maxnk . Tenga en cuenta que al hacer esto, en realidad está usando el contenedor como un Localizador de servicios, que no desacopla tanto como la inversión del control. (vea la diferencia aquí y aquí )

Espero que esto aclare tus dudas.