Vinicius Quaiato

{tecnologia, conceitos, negócios, idéias, práticas, .NET, ruby, osx, ios e algo mais}

Injeção de Dependência com MS Unity


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 {
}
", 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 UnityAs 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:

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:

[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));
    }
</enviadordeemails>

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:

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 {
}
", 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:

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 {
}
", 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.

Voltar

Fork me on GitHub