Você está na página 1de 4

Inverso de Controle (IoC) e

Injeo de Dependncia (DI)


no C#: desacoplando sua
aplicao e facilitando seus
testes
Por Jssica Schissato | 30 de agosto, 2013 | 11 comentrios
Quando vamos desenvolver uma aplicao, no basta simplesmente sair
escrevendo o cdigo sem antes persarmos em sua arquitetura. Existem
preocupaes que devemos considerar sobre o software, como por exemplo,
sua testabilidade, extensibilidade, manutenibilidade, etc. Isso tudo se torna
muito difcil quando temos um alto acoplamento entre as classes. E a que
entra a Inverso de Controle e a Injeo de Dependncia. Hoje vou explicar o
que so esses conceitos e como implementar em C#.

Inverso de Controle
Entendendo o problema
Para comear, precisamos entender o problema resolvido pela Inverso de
Controle (Inversion of Control ou IoC). Vamos imaginar a seguinte situao:
um controller Pedidos que utiliza o repositrio de pedidos para listar os
pedidos do banco de dados, por exemplo. Veja:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15

public class PedidosController : Controller


{
//
// GET: /pedidos/
public ActionResult Index()
{
var pedidoRepositorio = new PedidoRepository();
var pedidos = pedidoRepositorio.ObterTodos();
return View(pedidos);
}
}

O problema com o cdigo acima o alto acoplamento. A classe


PedidosController responsvel por instanciar o repositrio, por isso dizemos
que ela tem dependncia da classe PedidoRepository. Nesse caso, qualquer
alterao no repositrio de pedidos, vai afetar diretamente o controller. O
repositrio, por sua vez, utiliza uma conexo ao banco de dados para obter os
produtos, ento seu controller tambm est dependente disso! Voc pode
pensar que nunca ir mudar essa conexo, mas e seus testes unitrios? Eles
devem independer de acesso ao banco de dados, mas utilizando o cdigo
acima, ao testar seu controller de pedidos, ele ir instanciar a classe
repositorio que vai precisar da conexo.
Se voc desenvolve com TDD, j deve ter percebido o problema. Para testar o
controller acima, no conseguimos "mockar" o repositrio!

Como resolvemos esse problema?


Atravs da Inverso de Controle. Isso quer dizer que vamos inverter o
controle na classe PedidosController, tirando a responsabilidade dela sobre a
classe PedidoRepository e passando essa responsabilidade para outra classe,
interface, componente, etc.
Com isso, chegamos aos princpios do S.O.L.I.D, que define em sua letra D o
princpio de Inverso de Dependncia (Dependency Inversion):
Mdulos de alto nvel no devem depender de mdulos de baixo nvel, ambos
devem depender de abstraes.
Uma das formas de fazer a Inverso de Controle seguindo os princpios do
S.O.L.I.D, a Injeo de dependncia.

Injeo de Dependncia
A Injeo de Dependncia (Dependency Injection ou DI) um design
pattern para realizar a Inverso de Controle. Como j vimos acima, se a sua
classe depende de outra classe, ento devemos criar a dependncia para uma
classe abstrata. Com a sua classe dependendo de uma abstrao, devemos
injetar um objeto concreto nela.
De acordo com Martin Fowler em seu artigo sobre esse assunto, a Injeo de
Dependncia no a nica maneira de remover dependncias entre as
classes. Existe tambm o padro Service Locator, porm no tratarei dele
nesse post.

Injetando uma dependncia

Existem trs maneiras de injeo de dependncia:


Construtor (Constructor Injection): as dependncias do objeto so injetadas
diretamente em seu construtor.
Propriedade (Setter Injection): dependncias do objeto so injetadas via
setter em alguma(s) propriedade(s).
Interface: o objeto a ser injetado uma abstrao da classe concreta. (na
forma interface ou mesmo classe abstrata)
Vamos alterar nosso cdigo inicial do controller de Pedidos utilizando o
Constructor Injection. Criamos uma interface para o repositrio de pedidos,
IPedidoRepository, que o controller receber como parmetro no construtor.
1
2
public class PedidosController : Controller
{
3
private IPedidoRepository _pedidoRepositorio;
4
5
public PedidosController(IPedidoRepository pedidoRepositorio)
6
{
7
_pedidoRepositorio = pedidoRepositorio;
8
}
9
//
10
// GET: /pedidos/
11
12
public ActionResult Index()
13
{
14
var pedidos = _pedidoRepositorio.ObterTodos();
15
return View(pedidos);
16
}
17
18
19 }
20
Dessa forma, PedidosController dever ter a classe de repositrio injetada no
seu construtor. Com isso temos uma Inverso de Controle e estamos
respeitando o princpio do S.O.L.I.D, pois a classe est dependendo apenas da
abstrao da outra classe.
O cdigo acima compilado sem nenhum erro, porm ao executarmos esse
controller ocorrer um erro, j que no temos um construtor sem parmetros
definido e nenhuma interface sendo injetada na classe. Para resolvermos esse
problema vamos utilizar um terceiro elemento para injetar a dependncia do
controller, nesse caso utilizaremos o Ninject.

Ninject

O Ninject um framework de injeo de dependncia para aplicaes .NET. O


Ninject possui uma extenso para integrao com o ASP.NET MVC, o
Ninject.MVC3, que facilitar nosso trabalho. Voc pode baix-lo pelo prprio
NuGet atravs do comando:
1 install-package Ninject.MVC3
Aps instalar o Ninject, observe que o arquivo NinjectWebCommom.cs foi
adicionado na pasta App_Start. As configuraes do Ninject j esto prontas
para o MVC, portanto s precisamos registrar as dependncias dentro do
mtodo RegisterServices da seguinte maneira:
1 private static void RegisterServices(IKernel kernel)
2 {
kernel.Bind<IPedidoRepository>().To<PedidoRepository>();
3
}
4
E pronto! Nem precisamos criar uma classe que implementa a interface
IDependencyResolver, pois o Ninject.MVC3 j fez todo esse trabalho. Agora
quando rodarmos novamente a aplicao, no apresentar mais erro, pois ser
injetado uma classe concreta no controller.
Agora fica muito fcil "mockar" o repositrio, pois podemos passar o mock da
interface IPedidoRepository para o construtor do controller.

Concluso
Nesse post vimos os conceitos de Inverso de Controle e Injeo de
Dependncia, entendendo os problemas que eles resolvem e como
implementar em C#. Utilizamos o Ninject.MVC3 para facilitar nosso trabalho.
Os benefcios de utilizar esse padro com certeza ficaro cada vez mais
evidentes conforme sua aplicao aumenta de proporo e vai se tornando
mais complexa. Pode ser que voc gaste um pouquinho mais de tempo para
implementar a injeo de dependncia, mas com certeza ganhar mais tempo
na testabilidade e manutenibilidade da aplicao.

Referncias

http://martinfowler.com/articles/injection.html
http://viniciusquaiato.com/blog/injecao-de-dependencia/
http://www.linhadecodigo.com.br/artigo/3418/inversao-decontrole-ioc-e-injecao-de-dependencia-di-diferencas.aspx