18
Injeção de Dependência com MS Unity
Filed Under (.NET, Boas Práticas, Patterns) by Vinicius Quaiato on 18-01-2010
Tagged Under : DI, Injeção de Dependência, Inversão de Controle, IoC, 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 {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:

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.
Related posts:
- Injeção de Dependência no C# Hoje vamos falar um pouco sobre Injeção de Dependências no...
- Inversão de Controle (Inversion of Control / IoC) Fala galera, beleza? Escolhi falar de Inversão de Controle pois...
Show de bola Vinicius, ficou muito bem explicado e suscinto.
Parabens!
Abraço!
Muito bom,
Soh nao entendi como o unityContainer.Resolve injeta um “new SqlLogger()” dentro do EnviadorDeEmails.
Pois ao meu entendimento ficaria null dando erro no test.
Abraço
Então David, o contêiner é “esperto” o bastante pra saber como criar a classe, e caso ela possua alguma dependência ou parâmetros não fornecedos, o contêiner irá gerar uma exceção dizendo que não é possivel criar o tipo especificado.
Você pode por exemplo, definir para um tipo X que alguns parâmetros sejam passados ao ser contruído esse tipo X. Abordarei esse caso em um post futuro, fique no aguardo aew.
Abraços,
Vinicius Quaiato.
Muito interessante! Aonde posso ler mais sobre esse assunto (IoC, Injeção de dependência) ? Livro do Fowler?
[]s
Fala Thiago, beleza?
Não me lembro de nenhum livro específico do Fowler que fale sobre o assunto, mas existe literatura dele sobre isso aqui:
http://martinfowler.com/bliki/InversionOfControl.html
aqui:
http://martinfowler.com/articles/injection.html
Princípios SOLID por UncleBob aqui:
http://butunclebob.com/ArticleS.UncleBob.PrinciplesOfOod
Espero que possa ter ajudado.
Qualquer coisa, estamos aqui.
Att,
Vinicius Quaiato.