Olá amigos! No post anterior, fiz uma breve introdução em um padrão chamado Injeção de Dependência, no qual gosto muito e utilizo em meus projetos. Neste post de hoje vou tentar demonstrar como utilizar um container para realizar a injeção de dependência de forma simples e prática.
Existem várias bibliotecas que podem nos auxiliar com este processo, e particularmente tenho preferencial pela Microsoft Unity, pela facilidade que ela propõe. Existem outras como Ninject, Castle Windson, Spring.Net, entre outros.
Microsoft Unity
Inicialmente, o Unity fazia parte da Microsoft Enterprise Library, que até hoje é mantido pela Microsoft, que se trata de uma biblioteca de componentes (application block) que aplica as boas-práticas de desenvolvimento com .Net, práticas comuns do dia a dia como acesso a dados, validação, logging, entre outras. Com o Unity não foi diferente, passou a ser o bloco de injeção de dependência da Entreprise Library. Depois com o tempo, ele tornou-se independente e hoje estamos na versão 2.0. Você pode fazer o download do Microsoft Unity neste link.
http://www.microsoft.com/downloads/en/details.aspx?
FamilyId=2d24f179-e0a6-49d7-89c4-5b67d939f91b&displaylang=en
O Unity (assim como outras bibliotecas de injeção de dependência) fornece uma classe que tem como objetivo formar um Container de dependências, ou seja, em um container podemos registrar dependências que nosso software necessita e este por sua vez consegue construir objetos com estas dependências resolvidas.
Além da flexibilidade que ganhamos com a utilização de um container a produtividade aumenta, pois tudo no final parece ser um pouco mágico, bastando apenas solicitar um determinado tipo ao container que este nos retornara um objeto com suas dependências resolvidas e pronto para uso. Vamos a um exemplo prático.
Feito o download, instale o Unity em sua máquina de desenvolvimento e crie uma solução de testes no Visual Studio. Feito isso, adicione a referência do Unity (Microsoft.Pratices.Unity e Microsoft.Pratices.Unity.Interception.Configuration) como mostra na figura abaixo:

Figura 1: Adicionando referência para Microsoft Unity em projeto.
Feito isso, podemos começar a utilizar um container. Primeiramente vamos criar alguns exemplos para ilustrar o uso básico do container. A listagem abaixo, exibe um pequeno exemplo de uma interface para realizar log de aplicações e três simples implementações desta interface.
public interface ILogDeEvento
{
void Escrever(string mensagem);
void Escrever(string chave, string mensagem);
}
public class LogEvent : ILogDeEvento
{
public LogEvent() { }
private const string ChavePadrao = "MSUnitTest";
public void Escrever(string mensagem)
{
Escrever(ChavePadrao, mensagem);
}
public void Escrever(string chave, string mensagem)
{
// cria-se a chave caso esta ainda não exista.
if (!EventLog.SourceExists(chave))
{
EventLog.CreateEventSource(chave, "MSUnitTest");
}
//escreve no eventLog
var myLog = new EventLog { Source = chave };
myLog.WriteEntry(mensagem);
}
}
public class LogXml : ILogDeEvento
{
private const string Caminho = "LogXml.xml";
public void Escrever(string mensagem)
{
using (var stream = new StreamWriter(Caminho))
{
var xml = new XmlSerializer(typeof(string));
xml.Serialize(stream, mensagem);
}
}
public void Escrever(string chave, string mensagem)
{
Escrever(mensagem);
}
}
public class LogTxt : ILogDeEvento
{
public LogTxt()
{
}
private const string Caminho = "logDeEventos.log";
public void Escrever(string mensagem)
{
using (var stream = new StreamWriter(Caminho, true))
{
stream.WriteLine(mensagem);
stream.Flush();
}
}
public void Escrever(string chave, string mensagem)
{
using (var stream = new StreamWriter(Caminho, true))
{
stream.WriteLine(string.Format("{0}: {1}", chave, mensagem));
stream.Flush();
}
}
}
Listagem 1: Exemplo para implementação
Até aqui, nada de novo. Voltando ao projeto de testes, vamos adicionar um teste de unidade, a listagem abaixo demonstra como podemos utilizar o container da Microsoft Unity:
[TestClass]
public class UnityTest
{
// declaramos um container...
private IUnityContainer _container;
public UnityTest()
{
}
[TestInitialize()]
public void UnityInit()
{
// realizamos a instância deste container...
_container = new UnityContainer();
// registramos uma dependência no container...
_container.RegisterType(typeof (ILogDeEvento), typeof (LogTxt));
}
[TestCleanup()]
public void UnityDispose()
{
// liberamos o container do heap..
_container.Dispose();
}
[TestMethod]
public void Deve_Resolver_Dependencia()
{
// obtendo um logger de eventos pelo container...
var logger = _container.Resolve<ILogDeEvento>();
// invocando um método da instância resolvida pelo container...
logger.Escrever("Mensagem de erro para ser gerada em TXT.");
}
}
Listagem 2: Implementação do Teste utilizando Unity Container.
Como podemos observar no código acima, no escopo da classe temos uma declaração de um objeto da interface IUnityContainer, que é a interface implementada pelo nosso container. No método UnitInit (que possui o atributo [TestInitialize]) realizamos a instância deste objeto e registramos uma possível dependência passando dois tipos, onde o primeiro tipo é o requisitado e o segundo o que será utilizado para resolver. Observe que o tipo requisitado foi colocado a Interface ILogDeEventos (o que é uma boa prática da orientação a objetos, uma vez que podemos utilizar instâncias que implementam tal interface em sua concretização) e o tipo que a resolve é uma implementação dela LogTXT. Escrevemos um método de testes simples, Deve_Resolver_Depencias e neste implementamos a resolução deste tipo registrado pelo container, e se executarmos este teste, vemos nos resultados a saída do log em TXT. O mesmo vale se trocarmos o tipo de resolução para Xml ou EventLog.
Boas práticas com Injeção de Dependências.
Hoje em dia fala-se muito em realizar DI pelos construtores, propriedades ou métodos. Vou demonstrar aqui como realizar injeção de dependência pelo construtor, que na minha opinião é o tipo de dependência para um objeto que mais faz sentido, uma vez no construtor, sem tal dependência torna-se impossível construir o objeto.
Para ilustrar um exemplo disso, vamos criar uma classe que possui a implementação de um Logger, para um exemplo real, um Mock. A listagem abaixo exibe um pequeno exemplo abaixo:
public class Mock<T>
{
private readonly ILogDeEvento _eventLog;
public Mock(ILogDeEvento eventLog)
{
_eventLog = eventLog;
}
public void Salvar(T entidade)
{
// persistir objeto
_eventLog.Escrever(string.Format("Objeto {0} salvo com sucesso. \n Valor: {1}", entidade.GetType().Name, entidade.ToString()));
}
}
Listagem 3: Implementação de exemplo de Mock com dependência em construtor.
Observe que além de um classe genérica, no construtor deste recebemos um objeto da interface ILogDeEventos e setamos em uma variável interna no escopo da classe. Pois bem, voltando a classe de testes, vamos criar um novo método para realizar um simples deste exemplo. Veja o código comentado abaixo:
[TestClass]
public class UnityTest
{
// declaramos um container...
private IUnityContainer _container;
public UnityTest()
{
}
[TestInitialize()]
public void UnityInit()
{
// realizamos a instância deste container...
_container = new UnityContainer();
// registramos uma dependência no container...
_container.RegisterType(typeof (ILogDeEvento), typeof (LogTxt));
// registramos a dependência para o Mock genérico
_container.RegisterType(typeof(Mock<>), typeof(Mock<>));
}
[TestCleanup()]
public void UnityDispose()
{
// liberamos o container do heap..
_container.Dispose();
}
[TestMethod]
public void Deve_Resolver_Dependencia()
{
// obtendo um logger de eventos pelo container...
var logger = _container.Resolve<ILogDeEvento>();
// invocando um método da instância resolvida pelo container...
logger.Escrever("Mensagem de erro para ser gerada em TXT.");
}
[TestMethod]
public void Deve_Resolver_Dependencia_Em_Objeto()
{
// obtendo um Mock pelo container...
var mock = _container.Resolve<Mock<string>>();
// invocando um método da instância resolvida pelo container...
mock.Salvar("Felipe Oriani");
}
}
Listagem 4: Implementação do teste do uso do Mock junto ao Container de dependência.
A instância de um Mock tem o objeto de simular o comportamento de um objeto real de nossa aplicação e neste caso, estou utilizando este como um Repositório, que recebe em seu construtor um ILodDeEvento. Em nosso exemplo, estou registrando o Mock no container, pois este tem dependência (que devem ser resolvidas) e no método Deve_Resolver_Dependencia_Em_Objeto(), fiz um pequeno exemplo da crianção de um Repositório de Strings. Ao executar este teste, podemos olhar no output dos testes, que os logs são executados sem problemas, veja a imagem abaixo:

Figura 2: Resultado da saída do Log (em TXT).
Portando isso para uma aplicação do mundo real, se um dia resolvermos mudar nossa forma de realizar log da aplicação para XML ou EventLog, podemos simplesmente alterar a resolução para o container que funcionará sem problemas, uma vez que todas estas implementações de Log implementam a mesma interface, torna-se simples.
Bem pessoal o que gostaria de demonstrar neste post era isso.
Em um próximo post, pretendo abordar como utilizar o Unity no Asp.Net MVC para resolver dependências em Controllers e Repositórios de dados. Os exemplos utilizados neste post, estão no rodapé.
Vou deixar alguns links no final que utilizei como estudo e referência.
Espero que tenha gostado.
Abraços
Exemplo demonstrativo
MsUnityTests-Exemplo.zip (508,09 kb)
Links e Referências
http://en.wikipedia.org/wiki/Dependency_injection
http://www.hanselman.com/blog/ListOfNETDependencyInjectionContainersIOC.aspx
http://viniciusquaiato.com/blog/injecao-de-dependencia-com-ms-unity/
http://goo.gl/OKJIx