Desvendando a Injeção de Dependência no .NET
Tags: dotnet
Published: 2024-02-25 21:13:06

## Introdução

Se você é desenvolvedor .NET, certamente já ouviu falar sobre Injeção de Dependência (DI). No entanto, compreender profundamente esse conceito pode ser fundamental para criar aplicações mais flexíveis, testáveis e de fácil manutenção. Neste guia completo, vamos explorar a Injeção de Dependência no contexto do .NET, desde o que é até como aplicá-la eficientemente em seus projetos. Vamos começar desvendando os mistérios por trás desse conceito poderoso.

## O que é Injeção de Dependência

A Injeção de Dependência é um padrão de design fundamental para criar sistemas modularizados e de fácil manutenção. Em essência, trata-se de fornecer as dependências necessárias a uma classe a partir de uma fonte externa, em vez de criá-las internamente. Isso promove o desacoplamento entre componentes, facilitando a substituição, teste unitário e evolução do código ao longo do tempo.

## Como Funciona a Injeção de Dependência

No .NET, a Injeção de Dependência funciona por meio da passagem das dependências requeridas para os componentes dependentes, seja através do construtor, propriedades ou métodos. Essa prática possibilita a flexibilidade na escolha e alteração de implementações, proporcionando um código mais limpo e modular.

## Tipos de Injeção de Dependência

No ecossistema .NET, três métodos comuns para registrar serviços e gerenciar o ciclo de vida das dependências são AddScoped, AddTransient e AddSingleton. Cada um desses métodos tem suas características únicas que afetam a forma como as dependências são instanciadas e mantidas durante a execução da aplicação.

AddScoped: Cria uma instância por solicitação dentro do mesmo escopo (por exemplo, uma solicitação HTTP).

```
public interface IServicoScoped
{
    void ExibirMensagem();
}

public class ServicoScoped : IServicoScoped
{
    public Guid Id { get; } = Guid.NewGuid();

    public void ExibirMensagem()
    {
        Console.WriteLine($"Instância de Scoped - ID: {Id}");
    }
}

services.AddScoped<IServicoScoped, ServicoScoped>();
```


Neste exemplo, uma nova instância do serviço ServicoScoped será criada por solicitação HTTP. Dentro do mesmo escopo, a instância será a mesma para todos os componentes dependentes.

AddTransient: Cria uma nova instância sempre que a dependência é solicitada.


```
public interface IServicoTransient
{
    void ExibirMensagem();
}

public class ServicoTransient : IServicoTransient
{
    public Guid Id { get; } = Guid.NewGuid();

    public void ExibirMensagem()
    {
        Console.WriteLine($"Instância de Transient - ID: {Id}");
    }
}

services.AddTransient<IServicoTransient, ServicoTransient>();
```

Neste exemplo, uma nova instância do serviço ServicoTransient será criada sempre que a dependência for solicitada. Cada componente dependente receberá uma instância diferente.

AddSingleton: Cria uma única instância que é reutilizada em todas as solicitações durante a vida da aplicação.

```
public interface IServicoSingleton
{
    void ExibirMensagem();
}

public class ServicoSingleton : IServicoSingleton
{
    public Guid Id { get; } = Guid.NewGuid();

    public void ExibirMensagem()
    {
        Console.WriteLine($"Instância de Singleton - ID: {Id}");
    }
}

services.AddSingleton<IServicoSingleton, ServicoSingleton>();
```

Aqui, uma única instância do serviço ServicoSingleton será criada e reutilizada em todas as solicitações durante a vida da aplicação. Todas as partes dependentes compartilharão a mesma instância.

Entender quando usar cada um desses métodos é crucial para garantir o comportamento desejado de suas dependências ao longo do ciclo de vida da aplicação.