Um dos grandes problemas no desenvolvimento de software é a dependência entre classes que geramos durante o desenvolvimento. Classes são responsáveis por instanciar um objeto, delegar alguma tarefa e se encarregar de finalizar esse objeto. Existem diversas técnicas para mitigar esse problema, e uma das mais comuns é a injeção de dependências em conjunto com a inversão de controle.
O problema
public class ClasseA {
// Nesse caso, estamos criando a dependência, a utilizando, e a descartando.
// Assumindo assim, toda a responsabilidade.
public void Metodo() {
Dependencia dep = new Dependencia();
dep.FazAlgumaCoisa();
}
}
Inversão de Controle
Esse padrão consiste em: deixar o “dono” do objeto passar a dependência para a nossa classe, e assim, tiramos essa responsabilidade e tratamos somente o que importa para nosso método.
Para implementarmos com as melhores práticas, devemos sempre trabalhar com interfaces, pois nos prendemos à um contrato, e não à uma implementação.
Nossa nova versão da classe:
public class ClasseA {
private IDependencia _dep;
// Agora, nós precisamos que quem chama o método, passe algum objeto que cumpre o contrato
// e tiramos a responsabilidade de criação do objeto.
public ClasseA(IDependencia dep) {
_dep = dep;
}
public void Metodo() {
_dep.FazAlgumaCoisa();
}
}
É nesse contexto que a injeção de dependências entra em ação; nós delegamos para um módulo ou classe, o trabalho de saber qual é a implementação que desejamos passar para essa classe que depende dessa interface.
No ambiente .NET existem diversas bibliotecas para cumprir essa tarefa: Ninject, SimpleInjector, entre outros.
.NET Core e a injeção de dependências nativas
Quando estamos trabalhando com .NET Core, não há a necessidade de trabalharmos com essas bibliotecas, pois já temos uma implementação nativa de injeção de dependências!
Primeiramente, vamos supor que temos uma API que depende da nossa interface:
[Route("api/[controller]")]
public class ServicoController : Controller
{
private readonly IDependencia _dependencia;
// Estamos seguindo o padrão da inversão de controle para recebermos a nossa dependência
public ServicoController(IDependencia dep)
{
_dependencia = dep;
}
[HttpGet]
public IActionResult Get()
{
return Ok(_dependencia.FazAlgumaCoisa());
}
}
Agora, para habilitarmos a injeção dessa dependência de forma automática pelo .Net Core, vamos alterar nossa classe Startup.cs:
public class Startup
{
public void ConfigureServices(IServiceCollection services)
{
// Declaramos que quando alguma classe requisitar um IDependencia, devemos entregar um objeto do tipo Dependencia
services.AddTransient<IDependencia, Dependencia>();
// Demais linhas que já vem por default com o projeto omitidas
}
public void Configure(IApplicationBuilder app, IHostingEnviroment env) { ... }
}
Dessa maneira, ao chamarmos nossa API, receberemos um objeto do tipo Dependência como parâmetro. Note que usamos o método AddTransient, que cria um objeto novo a cada solicitação, mas existem outros métodos que criam o objeto em determinadas situações:
- AddTransient: cria um objeto a cada solicitação; se três objetos solicitarem a dependência, três instâncias são criadas.
- AddScoped: cria um objeto por request, se três objetos da mesma requisição solicitarem, os três objetos estarão lidando com a mesma instância, mas em uma segunda requisição, o objeto criado será outro.
- AddSingleton: cria somente um objeto, e este é compartilhado para todos os clientes que solicitarem a dependência.
Este é somente um artigo inicial sobre o tema, que possui muito conteúdo a ser explorado. A utilização de cada método depende da necessidade da sua aplicação e do contexto a ser lidado.
Espero que esse artigo tenha aberto um caminho para você explorar esse padrão e melhorar cada dia mais a qualidade das aplicações criadas.
Um forte abraço, e até logo!



