.NET - Usando o Framework UNITY  para Injeção de Dependência


Neste artigo vamos explicar passo a passo como usar Framework Unity Application Block (daqui em diante apenas Unity) que é um framework da Microsoft para aplicar o padrão de projeto Inversão de controle.

O Unity Application Block é um container para injeção de dependência extensível e leve que suporta injeção por construtor, por propriedade e por chamada de método. Você pode usá-lo com a Enterprise Library para gerar os objetos Enterprise Library e seus próprios objetos de negócios personalizados, ou seja, o Unity é parte da Enterprise Library mas pode ser usado sem ela e é isso que vamos fazer neste artigo.

O objetivo da inversão de controle e obter um baixo acoplamento, centralizar a configuração e permitir que os testes sejam realizados com mais facilidade.

"Módulos de nível mais alto não devem depender diretamente dos módulos de nível mais baixo. Ambos devem depender de abstrações."
"As abstrações não devem depender de detalhes de implementação, mas os detalhes devem depender de abstrações.".(Uncle Bob)

Os recursos usados neste artigo são:

  1. Visual C# 2010 Express Edition
  2. Unity Application Block 1.1 (atualmente já existe versão mais atualizada (2.1) mas eu vou usar a versão 1.1)-> http://unity.codeplex.com/

Criando o projeto

Abra o Visual C# 2010 Express Edition e crie um novo projeto do tipo Console Application com o nome UsandoUnity:

Após fazer o download do Unity 1.1 vamos incluir uma referência a ele em nosso projeto.

Selecione o projeto e no menu Project clique em Add Reference;

Na guia .NET selecione as referências a : Microsoft.Practices.Unity, Microsoft.Practices.Unity.Configuration e Microsoft.Practices.Unity.ObjectBuilder2 e clique em OK;

Após isso clique com o botão direito do mouse sobre o projeto e selecione Add -> New Item;

Selecione o template Interface e informe o nome IMembro.cs e clique em Add;

Agora vamos digitar o código abaixo nesta interface:

namespace UsandoUnity
{
    interface IMembro
    {
        string Nome
        {
            get;
            set;
        }
        string Time
        {
            get;
            set;
        }

        void Detalhes();
    }
}

Agora clique com o botão direito do mouse sobre o projeto e selecione Add -> New Item;

Selecione o template Class e informe o nome Membro.cs e clique em Add;

Digite o código abaixo nesta classe:

using System;

namespace UsandoUnity
{
    class Membro: IMembro
    {
          public Membro()
          { }      

          string _nome;
          string _nomeTime;     

         public string Nome
         {
             get
             {return _nome;}
             set
             {_nome = value;}
         }
         public string Time
         {
             get
             {return _nomeTime;}
             set
             {_nomeTime = value;}
         }
         public void Detalhes()
         {
             Console.WriteLine("Nome membro = \t" + _nome + " \tNome Time = \t" + _nomeTime);
         }
    }
}

Vamos agora criar uma classe Factory com o nome de Fabrica cuja responsabilidade será:

  1. Configurar o contâiner Unity;
  2. Registrar a interface como um tipo para o contâiner;
  3. Retornar uma instância do tipo registrado ou resolver um objeto pelo tipo;

Agora clique com o botão direito do mouse sobre o projeto e selecione Add -> New Item;

Selecione o template Class e informe o nome Fabrica.cs e clique em Add;

A seguir digite o código abaixo nesta classe:

using Microsoft.Practices.Unity;

namespace UsandoUnity
{

    class Fabrica
    {
        static public IMembro CreateInstance()
        {
            IUnityContainer _container = new UnityContainer();
            _container.RegisterType(typeof(IMembro), typeof(IMembro));
            IMembro obj = _container.Resolve<IMembro>();
            return obj;
        }
    }
}

Vamos entender o que foi feito:

Para configurar o contâiner Unity criarmos uma instância da classe UnityContainter():

IUnityContainer _container = new UnityContainer();

A seguir temos que registrar a interface como um tipo

  1. O método RegisterType da classe contâiner é usado para registrar um tipo no contâiner;
  2. No momento apropriado, o recipiente vai construir uma instância do tipo que é especificado;
  3. O tempo de vida do objeto construído vai corresponder ao tempo de vida especificado nos parâmetros do método;
  4. Se o tempo de vida não for especificado, o tipo será registrado por um tempo de vida transitório, o que significa que uma nova instância será criada em cada chamada para a resolver;

_container.RegisterType(typeof(IMembro), typeof(IMembro));
IMembro obj = _container.Resolve<IMembro>();
return obj;

Abaixo temos o código explicando como registramos o tipo:

falta resolver um objeto pelo tipo.

Para resolver um objeto pelo tipo vamos usar o método Resolve.

IMembro obj = _container.Resolve<IMembro>();

Quando este método é usado sem especificar um valor para a propriedade opcional name, o método retorna o objeto registrado com o mapeamento padrão.

Para resolver uma instância do tipo registrado fazemos assim:

IMembro obj = _container.Resolve<IMembro>();

Agora vamos por a coisa para funcionar incluindo o arquivo Program.cs o código abaixo:

using System;

namespace UsandoUnity
{
    class Program
    {
        static void Main(string[] args)
        {
            IMembro obj = Fabrica.CreateInstance();
            obj.Nome = " Macoratti ";
            obj.Time = " Brasil ";
            obj.Detalhes();
            IMembro obj1 = Fabrica.CreateInstance();
            obj.Nome = "Jefferson ";
            obj.Time = " Argentina ";
            obj.Detalhes();
            Console.Read();
        }
    }
}
using System;

namespace UsandoUnity
{
    class Program
    {
        static void Main(string[] args)
        {
            Membro obj = new Membro()
            obj.Nome = " Macoratti ";
            obj.Time = " Brasil ";
            obj.Detalhes();
            IMembro obj1 = new Membro();
            obj.Nome = "Jefferson ";
            obj.Time = " Argentina ";
            obj.Detalhes();
            Console.Read();
        }
    }
}
Usando Injeção de Dependência Sem usar Injeção de Dependência

Vamos entender o que esta acontecendo aqui:

IMembro obj = Fabrica.CreateInstance();

Na linha de código acima estamos usando o método CreateInstance() . O método CreateInstance() é um método estático e retorna uma instância do tipo registrado para o contâiner.

No código estamos criando do tipo Membro usando o contâiner Unity.

obj.Nome = " Macoratti ";
obj.Time = " Brasil ";
obj.Detalhes();

Agora propriedades e métodos da classe estão sendo chamado usando a instância da classe. Aqui cada chamada ao método Resolve está retornando uma instância do tipo registrado.

O resultado da execução pode ser visto abaixo:

Com isso vimos que podemos usar o contâiner Unity para aplicar a injeção de dependência. Estamos injetando a dependência passando a classe que será utilizada para a classe que será consumida.

Note que no método Main() não criamos uma instância da classe Membro usando o operador new() ao invés estamos fazendo isso usando o contâiner Unity.

Existem outros contâiners para injeção de dependência como: Spring .NET, Ninject, Castle Windsor, Autofac, etc.

Pegue o projeto completo aqui: UsandoUnity.zip

Salmos 5:1 Dá ouvidos às minhas palavras, ó Senhor; atende aos meus gemidos.
Salmos 5:2
Atende à voz do meu clamor, Rei meu e Deus meu, pois é a ti que oro.
Salmos 5:3
Pela manhã ouves a minha voz, ó Senhor; pela manhã te apresento a minha oração, e vigio.

Salmos 5:4
Porque tu não és um Deus que tenha prazer na iniqüidade, nem contigo habitará o mal.

Referências:


José Carlos Macoratti