Inversión de Control ( IoC ) y Contenedor IoC en ASP.NET MVC
Un Inversor de Control (IoC para simplificar) es un patrón de diseño que coadyuva al bajo acoplamiento entre componentes de un sistema o una aplicación.
Un IoC es una herramienta muy útil para implementar un sistema enfocado a un diseño orientado a componentes ya que nos proporciona la flexibilidad necesaria para implementar un diseño libre de dependencias entre componentes.
Un ejemplo claro de un diseño orientado a componentes son los componentes electrónicos, donde un componente en ningún momento se preocupa de cómo funciona internamente el otro componente con el que interactúa y donde solo le importa el servicio que proporciona y si la interfaz con la que proporciona el servicio es compatible con la suya.
Volviendo al diseño de software supongamos que tenemos una clase llamada “RepositorioSQL”, otra llamada “Usuario” y otra “Log”. La clase “Usuario” tiene entre sus propiedades las definiciones de las otras clases:
public class Usuario
{
private RepositorioSQL _repositorio;
private Log _log;
//resto de la clase...
}
Viendo la clase podemos deducir que es una clase con alta dependencia de código con las otras clases ya que si en algún momento deseamos cambiar, por ejemplo el manejar de base de datos, esto traería como consecuencia cambiar también la clase “RepositorioSQL”, por otra que sea mas adecuada al nuevo manejador de base de datos, entonces tendríamos que cambiar todas las apariciones de la clase “RepositorioSQL” en la clase usuario, esto no acompaña a los preceptos de bajo acoplamiento de un diseño orientado a componentes. Ahí es donde IoC entra en acción, con el podemos definir la clase de arriba de la siguiente manera:
public class Usuario
{
private IRepositorioSQL _repositorio;
private ILog _log;
public Usuario(IRepositorio repositorio, ILog log)
{
this._repositorio=repositorio;
this._log=log;
}
//resto de la clase...
}
Ahora las clases “RepositorioSQL” y “Log” se han convertido en interfaces y como sabemos las interfaces solo definen los métodos y no así una implementación concreta de estos, con lo cual nos es más fácil hacer el cambio, pero hay un pequeño problema en este punto cuando instanciemos la clase “Usuario” deberemos enviar como parámetros de construcción las implementaciones concretas de las interfacespero si hacemos esto solo habríamosmovido el problema de un lado a otro, no siendo esto una solución a nuestro problema.Para tener una verdadera independencia de componentes debemos usar un nuevo juguete llamado “Contenedor de IoC”.
Un contenedor IoC es un componente de software que nos ayuda a manejar y soportar un IoC sin problema, gracias a que nos permite almacenar en el los componentes que deseemos y luego en base a las directivas que nosotros definamos (por lo general en archivos XML) instanciara los componentes adecuados.
Para cubrir la tarea antes descrita un contenedor IoC posee las características de “Resolución de Cadenas de Dependencia”, “Manejador de tiempos de vida de los Objetos” y “Configurador de valores para parámetros explícitos en Constructores”.
La primera característica resuelve las dependencias de los componentes en cadena o en pila, como por ejemplo si un primer componente depende de un segundo componente y este a su vez depende de un tercer componente, estas dependencias son resueltas recursivamente por el contenedor IoC.
La segundo característica como su nombre dice se encargara de definir los tiempos de vida de los objetos y la cantidad de veces que se instanciara para cumplir un requerimiento especifico, por lo general nosotros definiremos esto en el archivo XML del contenedor.
La ultima característica ayudara a que podamos definir un valor especifico (por lo general en el archivo XML del contenedor) para que sea provisto al constructor de una clase. Un ejemplo común de esto es cuando una clase pide como parámetro la cadena de conexión a una base de datos.
Puesta a punto de un Contenedor IoC con Castle Project (Windsor)
El proyecto Castle es un proyecto open source que nos ofrece muchas herramientas para que el desarrollo de aplicaciones sea fácil y haciendo énfasis en las buenas practicas de programación. Para poder usar el contenedor de IoC de este proyecto deberemos de bajarnos el instalador de aquí. El instalador registrara los ensamblados del proyecto (dlls) en nuestra GAC (Global Assembly Cache) de Visual Studio, para que podamos usarlos en nuestros proyectos.
Después de instalar los ensamblados debemos probar como funcionan y como hay que configurar el Contenedor IoC, para lo cual vamos a crear un nuevo proyecto en nuestro Visual Studio del tipo ASP.NET MVC Application, después de haber creado el proyecto vamos a referenciar los siguientes ensamblados:
- Castle.Core
- Castle.MicroKernel
- Castle.Windsor
Estos ensamblados nos dan acceso al contenedor IoC del proyecto Castle llamado WindsorContainer.
El próximo paso consta de crear un nuevo “Controller Factory”, que básicamente es una clase heredada de “DefaultControllerFactory” que en su constructor busca a todos los tipos “Controller” y los registra como componentes de nuestro contenedor IoC(Esta clase solo es necesaria para aplicaciones web hechas con ASP.NET MVC):
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
using Castle.Windsor;
using Castle.Windsor.Configuration.Interpreters;
using Castle.Core.Resource;
using System.Reflection;
using Castle.Core;
namespace WebUI
{
public class WindsorControllerFactory: DefaultControllerFactory
{
//Definimos el contenedorIoC
WindsorContainer container;
public WindsorControllerFactory()
{
//Creamos el contenedor IoC en base a un archivo de configuracion XML
container = newWindsorContainer(newXmlInterpreter(newConfigResource("castle")));
//Accedemos a los ensamblados en ejecución y buscamos los tipos "IController"
var controllerTypes = from t inAssembly.GetExecutingAssembly().GetTypes()
where typeof(IController).IsAssignableFrom(t)
select t;
foreach (Type t incontrollerTypes)
{
//Agregamos los objetos del tipo "IControllers" como componentes, con un tiempo de vida Transitorio
container.AddComponentWithLifestyle(t.FullName, t, LifestyleType.Transient);
}
}
//Método que nos devuelve las instancias de los tipos "IController"
protected override IController GetControllerInstance(System.Web.Routing.RequestContextrequestContext, TypecontrollerType)
{
return (IController)container.Resolve(controllerType);
}
}
}
Nuestro siguiente paso seria abrir el archivo web.config(para aplicaciones win32 debemos abrir el archivo app.config) y en la sección configSection agregar un nodo llamado Castle:
<configSections>
<sectionname="castle"type="Castle.Windsor.Configuration.AppDomain.CastleSectionHandler, Castle.Windsor" />
//El resto de nodos
configSections>
Luego en el nodo configuration agregamos un nodo llamado “Castle”, en este nodo definiremos todos los componentes que deseamos registrar:
<castle>
<components>
<component>
//Aquí van tus componentes
component>
components>
castle>
Por últimos nos vamos al archivo Global.asax.cs y en el método “Application_Start” ponemos lo siguiente:
protected void Application_Start()
{
RegisterRoutes(RouteTable.Routes);
ControllerBuilder.Current.SetControllerFactory(newWindsorControllerFactory());
}
Ahora si hacemos correr el programa debería de funcionar correctamente o como estaba cuando empezamos a realizar la configuración del contenedor. Como ven configurar un contenedor IoC con el proyecto Castle es muy fácil.
Suerte!.
Comentarios
Publicar un comentario