Inyección de dependencias en ASP.NET MVC con Castle

by Luis Roig on noviembre 14th, 2010

Llevo ya tiempo queriendo dedicar un post a hablar un poco sobre el patrón de diseño de Inyección de Dependencias y de cómo podemos beneficiarnos de él, en este caso con uno de los frameworks de desarrollo web con el que estoy trabajando últimamente: ASP.NET MVC.

Según la wikipedia: “Inyección de Dependencias (en inglés Dependency Injection, DI) es un patrón de diseño orientado a objetos, en el que se suministran objetos a una clase en lugar de ser la propia clase quien cree el objeto”. Es decir, típicamente tendremos reunidos en una clase ciertos métodos que nos son útiles en varios sitios de nuestra aplicación (por ejemplo un sistema de Logging, o de acceso a base de datos) que para aclararnos vamos a llamar clase servicio.

Pero con los mecanismos que nos ofrece cualquier lenguaje orientado a objetos, si queremos usar esta clase nos tocará instanciar un objeto de esta clase servicio dentro de otra clase para usarla. Esto tiene un efecto no muy deseable, y es que estamos haciendo totalmente dependientes nuestras clases de la clase servicio. Si en vez de la clase servicio que usaba hasta ahora para el sistema de logging quiero usar otra, en todas las clases que accedan a ella tendré que cambiar el tipo que se instancia y volver a compilarlas (en caso de que no estemos usando un lenguaje interpretado).

¿No podríamos mejorar esto haciendo que los componentes de nuestra aplicación no sean tan dependientes entre ellos?. La solución es el patrón de Inyección de dependencias. La idea es que en los componentes de nuestra aplicación simplemente especifiquen los servicios que necesitamos y por detrás haya un framework que provea estos servicios. En el mundo Java la opción clásica para este framework sería Spring, y para .NET/Mono nosotros vamos a usar otra opción también open source que es Castle Windsor.

Vamos a ver un pequeño ejemplo de cómo podriamos configurar un servicio que consumirán nuestros controladores. Vamos a usar una forma bastante sencilla de hacer esto, aunque Castle nos ofrece otras muchas. En el Global.asax de nuestra aplicación ASP.NET MVC normalmente tendremos lo siguiente:

protected void Application_Start() {
    AreaRegistration.RegisterAllAreas();
    RegisterRoutes(RouteTable.Routes);
}

Nosotros vamos a añadir un método BuildContainer en el que simplemente inicializaremos el contenedor de Castle Windsor y le añadiremos un componente que podrán recibir las clases de nuestra aplicación en el constructor. Además debemos añadir una variable estática y privada que contenga el contenedor de nuestra aplicación:

private static IWindsorContainer Container;
 
protected void Application_Start() {
    BuildContainer();
    AreaRegistration.RegisterAllAreas();
    RegisterRoutes(RouteTable.Routes);
}
 
private void BuildContainer() {
    Container = new WindsorContainer();
    Container.RegisterControllers(typeof(HomeController).Assembly);
    ControllerBuilder.Current.SetControllerFactory(new WindsorControllerFactory(Container));
    Container.Kernel.AddComponent(
        "MvcApplication.Services.MyService", 
        typeof(IService), typeof(MyService), 
        LifestyleType.Transient);
}

Además de usar Castle Windsor, hemos hecho uso de la libreria open source MvcContrib.Castle, que extiende Windsor para proporcionarnos algunos métodos utiles para registrar nuestros controladores en el contenedor e indicar a Castle que consumirán servicios (son las llamadas que vemos a Container.RegistrerControllers y WindsorControllerFactory). Por último hemos registrado un componente indicando la clase a la que corresponde y el interfaz que implementa.

Ahora simplemente incluiremos el servicio en el constructor de nuestro controlador, Windsor se encargará de inyectar esa dependencia y ya lo podremos usar tranquilamente desde nuestras acciones:

public class HomeController : Controller {
        private IService _myService;
 
        public HomeController(IService myService) {
            _myService = myService;
        }
 
        public ActionResult Index() {
            _myService.DoSomething(); 
            return View();
        } 
}

La ventaja de trabajar con interfaces es que cuando queramos podemos cambiar MyService por otra clase que implemente este interfaz, sin afectar al código de las clases que consumen dicho servicio. Además, típicamente configuraremos los componentes del contenedor mediante un fichero de configuración xml y no por código como hemos hecho en este ejemplo, con lo que nuestra aplicación será todavia más flexible.

From → Sin categoría

3 Comentarios
  1. taak permalink

    Oye de casualidad no tienes algún otro Ejemplo un poco mas complejo en cuanto a la implementación de Castle.

  2. Maite permalink

    Muy buena explicación. Muchas gracias.

  3. Pablo permalink

    Tendrías otro ejemplo donde dos clases implementen la misma interfaz y tengan los mismos métodos con resultados diferentes?

Escribe un comentario!

Nota: Se permite XHTML. Tu email nunca se publicará.

Suscríbete a este feed de comentarios via RSS