Archivos de la categoría ‘Dependency Injection’

Igual que hice en otro post con Ninject, voy a hacer un ejemplo de cómo usas Inyección de Dependencias con Unity.

Unity es una librería que viene dentro de Enterprise Library 5.0, que os podéis descargar desde aquí. Recomiendo que os bajéis la versión con código fuente, ya que en caso de errores siempre la podréis debugar.

Como en el ejemplo con Ninject, creamos un proyecto de consola, en este caso se llamará DI_Unity, y añadimos las siguientes referencias:

Microsoft.Practices.Unity
Microsoft.Practices.Unity.Configuration
System.Configuration

Esta última la utilizaremos para leer del fichero de configuración la implementación que queramos usar, pero me estoy adelantando, vamos primero a por el código.

Añadimos al proyecto los siguentes elementos:

– Interfaz IRepository

namespace DI_Unity
{
    interface IRepository
    {
        string GetData();
        bool Save();
    }
}

– Clases SQLRepository y OracleRepository, que son las que implementan la interfaz IRepository.

 class SQLRepository : IRepository
    {
        #region IRepository Members

        public string GetData()
        {
            return "GetData from SQLRepository";
        }

        public bool Save()
        {
            return true;
        }

        #endregion
    }


class OracleRepository : IRepository
    {
        #region IRepository Members

        public string GetData()
        {
            return "GetData from OracleRepository";
        }

        public bool Save()
        {
            return false;
        }

        #endregion
    }

– Clase MyService, que es la que recibe la inyección de dependencias.

 class MyService
    {        
        private readonly IRepository _repository;

        public MyService(IRepository repository)
        {
            _repository = repository;
        }

        public string GetData()
        {
            return _repository.GetData();
        }

        public bool Save()
        {
            return _repository.Save();
        }
    }

– App.config, en este fichero definiremos qué implementación vamos a usar cuando se necesite un objeto de tipo IRepository.

<?xml version="1.0" encoding="utf-8" ?>
<configuration>
  <configSections>
    <section name="unity" type="Microsoft.Practices.Unity.Configuration.UnityConfigurationSection, Microsoft.Practices.Unity.Configuration"/>
  </configSections>

  <unity xmlns="http://schemas.microsoft.com/practices/2010/unity">
    <alias alias="IRepository" type="DI_Unity.IRepository, DI_Unity" />
    <namespace name="DI_Unity" />
    <assembly name="DI_Unity" />

    <container name="repository">
      <register type="IRepository" mapTo="SQLRepository"/>
    </container>

  </unity>

</configuration>

Como podéis ver, en el fichero de configuración declaramos un tipo IRepository y un elemento <container> en el que se especifica qué clase mapea a IRepository en tiempo de ejecución.

Ahora vamos a la clase Program.cs para hacer una llamada a nuestro servicio:

using System;
using Microsoft.Practices.Unity;
using Microsoft.Practices.Unity.Configuration;
 
namespace DI_Unity
{
    class Program
    {
        static void Main(string[] args)
        {
            // Carga el container "repository" donde declaramos la implementación 
            // de IRepository que queremos utilizar
            IUnityContainer container = new UnityContainer();
            container.LoadConfiguration("repository");
 
            // Le decimos a Unity que resuelva la implementación
            MyService service = new MyService(container.Resolve<IRepository>());
 
            // Llamamos a un método del servicio
            Console.WriteLine(service.GetData());
 
            Console.ReadKey();
        }
    }
}

Ejecutamos y obtendremos «Get Data from SQLRepository» 🙂 Para utilizar la otra clase únicamente tendremos que cambiar en el fichero de configuración (en nuestro caso App.config), esta linea:

<register type="IRepository" mapTo="SQLRepository"/>

por esta otra:

<register type="IRepository" mapTo="OracleRepository"/>

Si os interesa profundizar en cómo usar Unity con archivos de configuración podéis echar un vistazo a este link: Using Design-Time Configuration

Happy codding 😉

Enlaces relacionados:

¿Qué es la Inyección de Dependencias?

How to: Inyección de dependencias con Ninject

Using Design-Time Configuration

No me gusta enrollarme con definiciones, así que si queréis saber ¿qué es eso de la Inyección de Dependencias? hacer click en este enlace de la wikipedia.

Lo que sí voy a explicar es cómo implementarlo con la librería Ninject y .NET Framework 3.5.
Será un ejemplo muy sencillo en el que un servicio (MyService) utilizará una clase repositorio (para por ejemplo, conectarse a una base de datos) de un tipo u otro dependiendo de lo que le indiquemos a Ninject.

Vamos por faena, creamos un proyecto de consola, que llamaremos DI_Ninject.

Nos bajamos la librería Ninject (descargar aquí), la versión 2.0 para el .NET Framework 3.5, y la guardamos en un directorio dentro de la solución.

Añadimos una referencia a la librería Ninject: Project -> Add Reference y buscamos la dll que nos hemos descargado.

Y ahora el código, añadimos los siguientes elementos al proyecto:

– Interface IRepository

namespace DI_Ninject
{
    interface IRepository
    {
        string GetData();
        bool Save();
    }
}

– Clase SQLRepository

namespace DI_Ninject
{
    class SQLRepository : IRepository
    {
        #region IRepository Members

        public string GetData()
        {
            return "GetData from SQLRepository";
        }

        public bool Save()
        {
            return true;
        }

        #endregion
    }
}

– Clase Oracle Repository

namespace DI_Ninject
{
    class OracleRepository : IRepository
    {
        #region IRepository Members

        public string GetData()
        {
            return "GetData from OracleRepository";
        }

        public bool Save()
        {
            return false;
        }

        #endregion
    }
}

Ya veis que la única diferencia entre SQLRepository y OracleRepository es el texto que devuelve, pero para un ejemplo es más que suficiente.

– Clase MyService

using Ninject;

namespace DI_Ninject
{
    class MyService
    {
        private readonly IRepository _repository;

        [Inject]
        public MyService(IRepository repository)
        {
            _repository = repository;
        }

        public string GetData()
        {
            return _repository.GetData();
        }

        public bool Save()
        {
            return _repository.Save();        
        }
    }
}

Aquí empieza lo bueno, como veis el constructor de la clase MyService recibe un parámetro de tipo IRepository y lo guarda en una campo privado (_repository). El hecho de poner el atributo [Inject] en el constructor es lo que hace que Ninject sepa que tiene que hacer algo con ese parámetro. Pero ¿cómo?

Es bien sencillo, primero creamos una clase:

 class MyModule : Ninject.Modules.NinjectModule
    {
        public override void Load()
        {
            Bind<IRepository>().To<SQLRepository>();
        }
    }

que es la que indica qué implementación de IRepository se va a utilizar. Como veis, en este caso se usará SQLRepository.

Y ahora lo único que nos falta es llamar al servicio y ver qué nos devuelve:

 class Program
    {
        static void Main(string[] args)
        {
            // Iniciamos el kernel de Ninject con nuestro módulo
            // que es donde establecemos las relaciones interface-clase
            Ninject.Modules.INinjectModule module = new MyModule();
            Ninject.IKernel kernel = new StandardKernel(module);

            // Creamos una instancia de MyService a través del kernel
            MyService service = kernel.Get<MyService>();

            // Llamamos a uno de los métodos del servicio
            Console.WriteLine(service.GetData());

            Console.ReadKey();
        }
    }

Y ejecutamos. La consola nos mostrará el texto «GetData from SQLRepository», que es lo que devuelve el método GetData de SQLRepository. Pero nosotros no hemos creado ningún objeto de este tipo :O

Ahí está la mágia de la inyección de dependencias 🙂

 

¿Cómo se probaría la otra implementación (OracleRepository)?, pues tan fácil como cambiar:

Bind<IRepository>().To<SQLRepository>();

por

Bind<IRepository>().To<OracleRepository>();

en MyModule.cs, y ejecutar, podemos ver que el resultado es «GetData from OracleRepository» 🙂

Y eso es todo por ahora. Por supuesto el binding entre la interface y las clases se podría hacer de otra forma por ejemplo leyéndolo de un fichero de configuración o de un parámetro al llamar al kernel de Ninject, pero eso ya os lo dejo para que lo investiguéis. Tenéis más info en la wiki de Ninject

Happy codding 😉