Injeção de Dependência com MS Unity

Filed Under (.NET, Boas Práticas, Patterns) by Vinicius Quaiato on 18-01-2010

Tagged Under : , , , ,

Bom pessoal, pudemos ver os benefícios e alguns usos de Inversão de Controle e Injeção de Dependências aqui e aqui.

Uma das formas de obter excelentes ganhos com a inversão de controle é através da utilização de um contêiner de Injeção de Dependências.

Um contêiner de injeção de dependências é capaz de criar objetos com todas suas dependências injetadas e totalmente pronto para uso. Em geral estes conteiners podem ser configurados manualmente(programaticamente) ou dinamicamente(através de arquivos de configuração por exemplo).

Falaremos um pouco do Unity que é um contêiner de Injeção de Dependência que faz parte dos Application Blocks da Microsoft.

Para que vejamos como o Unity funciona faça o download do mesmo aqui e execute o setup, que irá apenas criar uma pasta com as DLLs do Unity.

O Unity, como veremos nos exemplos, suporta 3 tipos de injeção de dependência:

  • Constructor Injection (injeção por construtor)
  • Property Injection (injeção de propriedade)
  • Method Call Injection (injeção de chamada de métodos)

Vamos usar como exemplo estas classes e interfaces:

public interface ILogger
{
    void RegistrarMensagem(string mensagem);
}
 
public class SqlLogger : ILogger
{
    public void RegistrarMensagem(string mensagem)
    {
        //abre conexão SQL
 
        //Executa insert da mensagem
    }
}
 
public class EnviadorDeEmails
{
    public ILogger Logger { get; set; }
    public EnviadorDeEmails(ILogger logger)
    {
        this.Logger = logger;
    }
    public void EnviarEmail(string email, string mensagem)
    {
        //Envia email
 
        //registra envio
        this.Logger.RegistrarMensagem(string.Format("Email enviado para {0}", email));
    }
}

Adicione as seguintes referências ao seu projeto: Microsoft.Practices.ObjectBuilder2.dll e Microsoft.Practices.Unity.dll que se encontram na pasta que você “instalou” o Unity, como pode ser visto na figura abaixo:
Incluindo Dlls do Unity

As classes acima são bem simples, no final das contas o que faremos é com que o Unity crie um EnviadorDeEmails com a dependência de ILogger injetada e resolvida, ou seja, que ele crie um EnviadorDeEmails passando para ele um SqlLogger. Para isso vamos “ensinar” ao Unity como resolver a interface ILogger, como pode ser visto no código abaixo:

1
2
    var unityContainer = new UnityContainer();
    unityContainer.RegisterType<ILogger, SqlLogger>();

Na linha 1 criamos uma instância do contêiner do Unity. Na linha 2 dizemos para o Unity que quando quisermos o tipo ILogger (interface) ele deve utilizar a classe concreta SqlLogger. Simples assim.

Constructor Injection

Agora podemos mandar que o Unity construa nosso EnviadorDeEmails usando constructor injection, conforme visto abaixo:

1
2
3
4
5
6
7
8
9
10
[TestMethod]
public void Configurando_Unity_Para_Resolver_ILogger()
{
    var unityContainer = new UnityContainer();
    unityContainer.RegisterType<ILogger, SqlLogger>();
 
    var enviadorEmails = unityContainer.Resolve<EnviadorDeEmails>();
 
    Assert.IsInstanceOfType(enviadorEmails.Logger, typeof(SqlLogger));
}

O grande segredo aí está na linha 7 onde dizemos para o Unity construir nosso EnviadorDeEmails. O Unity percebe que existe uma dependência no construtor do EnviadorDeEmails, e baseado na configuração que fizemos ele sabe como resolver esta dependência. Na linha 9 apenas verificamos se de fato o ILogger utilizado é o SqlLogger, e executando o teste obtemos sucesso.
E notem que neste caso utilizamos o constructor injection pois a classe EnviadorDeEmails possui um construtor com uma dependência para uma interface, que o Unity conhece.

Property Injection

Poderíamos dizer que a dependência não deve ser resolvida via construtor, mas sim diretamente na propriedade, para isso alteraríamos a classe EnviadorDeEmails assim:

1
2
3
4
5
6
7
8
9
10
11
12
public class EnviadorDeEmails
{
    [Dependency]
    public ILogger Logger { get; set; }
    public void EnviarEmail(string email, string mensagem)
    {
        //Envia email
 
        //registra envio
        this.Logger.RegistrarMensagem(string.Format("Email enviado para {0}", email));
    }
}

A única diferença aqui foi a utilização do DependencyAttribute na linha 3 para marcar que a propriedade Logger, do tipo ILogger, deve ser resolvida pelo Unity.
Executando nosso teste mais uma vez devemos obter sucesso.

Method Call Injection

A outra forma que o Unity tem para injetar nossas dependências é através da chamada de um método. Por exemplo, imaginem que temos um método Initialize na nossa classe, que é responsável por criar os objetos que nossa classe precisa. Podemos fazer com que o Unity execute este método resolvendo todas as dependências.
Vejamos o código da classe EnviadorDeEmails utilizando um Method Call Injection:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
public class EnviadorDeEmails
{
    public ILogger Logger { get; set; }
    public void EnviarEmail(string email, string mensagem)
    {
        //Envia email
 
        //registra envio
        this.Logger.RegistrarMensagem(string.Format("Email enviado para {0}", email));
    }
 
    [InjectionMethod]
    public void Inicializador(ILogger logger)
    {
        this.Logger = logger;
    }
}

Tudo o que fizemos desta vez foi criar um método, neste caso o método Inicializador, na linha 13, que recebe como parâmetros as dependências da nossa classe. E marcamos este método com o InjectionMethodAttribute, para dizer ao Unity que este método deve ser chamado e resolvidor por ele na criação de nosso EnviadorDeEmails.
E novamente se executarmos o mesmo método de teste, obteremos sucesso.

Como vimos nos três exemplos acima, o Unity após configurado consegue resolver as dependências de nossas classes de forma simples e trivial. Basta alterarmos a forma de resolução da dependência, por exemplo de constructor para setter, e nada no código mudará, assim como se mudar de SqlLogger para XmlLogger, nada no código mudará, apenas a configuração do Unity.

Bom galera, é mais ou menos isso. O Unity é uma ferramenta bastante poderosa, extensível e simples de usar.

Qualquer dúvida é só escrever nos comentários ou enviar email.

Abraços,
Vinicius Quaiato.