netcore8.webp

Neste artigo vamos explorar a Injeção de Dependência no .Net Core através do registro de um serviço através de uma Classe e de uma Interface. Praticaremos as duas formas de implementação criando um projeto do início e executando para analisarmos os resultados.

Introdução

Quando um aplicativo ASP.NET Core recebe uma solicitação HTTP, o código que manipula a solicitação às vezes precisa acessar outros serviços. Por exemplo, um componente Blazor pode precisar acessar um serviço que busca dados de um banco de dados. O ASP.NET Core usa o DI (injeção de dependência) integrado para gerenciar os serviços que um aplicativo usa.

Criando o projeto para este artigo

Além de estudarmos a Injeção de Dependência, vamos criar um projeto a aplicar a injeção de forma prática. Vamos analisar e ver esta teoria se transformando em informação e “telas” na nossa frente.

Como já vimos anteriormente, existem inúmeras maneiras de criar um projeto .Net Core, vamos escolher hoje a criação de um projeto via CLI.

Em sua pasta de repositórios comum, execute o comando abaixo, após a execução, acesse a pasta do projeto criado e abra a solução em sua IDE de preferẽncia. Para demonstração neste artigo usaremos o visual studio code. Para abrir a solução, apenas digite o comando code . e o visual studio code será aberto.

dotnet new webapi --name EstudoInjecaoDependencia

Após a criação do projeto e abertura do mesmo em sua IDE, teremos o resultado semelhante ao da imagem abaixo, com o projeto e toda sua estrutura na seção Solution Explorer.

estudo-injecao-1.png

Para validarmos a criação e executarmos pela primeira vez nossa aplicação, basta pressionar F5, selecionar C# com configurações padrão e uma janela no navegador será aberta com o swagger. Teremos um resultado semelhante ao abaixo:

estudo-injecao-2.png

Entendendo a Injeção de Dependência e aplicando pela primeira vez

Os aplicativos ASP.NET Core geralmente precisam acessar os mesmos serviços em vários componentes. Por exemplo, vários componentes podem precisar acessar um serviço que busca dados de um banco de dados. O ASP.NET Core usa um contêiner DI (injeção de dependência) integrado para gerenciar os serviços que um aplicativo usa.

O padrão de injeção de dependência é uma forma de Inversão de Controle (IoC). No padrão de injeção de dependência, um componente recebe suas dependências de fontes externas em vez de criá-las ele mesmo. Esse padrão separa o código da dependência, o que torna o código mais fácil de testar e manter.

Considere o Program.cs abaixo:

using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.DependencyInjection;
using MyApp.Services;

var builder = WebApplication.CreateBuilder(args);
    
builder.Services.AddSingleton<PersonService>();
var app = builder.Build();

app.MapGet("/", 
    (PersonService personService) => 
    {
        return $"Olá {personService.GetPersonName()}!";
    }
);
    
app.Run();

E considere o arquivo PersonService.cs abaixo:

namespace MyApp.Services;

public class PersonService
{
    public string GetPersonName()
    {
        return "você, estudando Injeção de Dependência";
    }
}

Vamos entender os trechos de código acima:

Para entender o código, comece com o código app.MapGet. Este código mapeia solicitações HTTP GET para a URL raiz (/) para um delegate que retorna uma mensagem de saudação. A assinatura do delegate define um parâmetro PersonService denominado personService. Quando o aplicativo é executado e um cliente solicita a URL raiz, o código dentro do delegate depende do serviço PersonService para obter algum texto para incluir na mensagem de saudação.

Onde o delegate obtém o serviço PersonService? É fornecido implicitamente pelo contêiner de serviço. A linha builder.Services.AddSingleton<PersonService>() destacada informa ao contêiner de serviço para criar uma nova instância da classe PersonService quando o aplicativo for iniciado e fornecer essa instância a qualquer componente que precise dela.

Qualquer componente que necessite do serviço PersonService pode declarar um parâmetro do tipo PersonService em sua assinatura de delegate. O contêiner de serviço fornecerá automaticamente uma instância da classe PersonService quando o componente for criado. O delegate não cria a instância PersonService em si, apenas usa a instância que o contêiner de serviço fornece.

Vamos colocar em prática esta Injeção de Dependência em nossa aplicação

Crie uma nova classe em sua solução. Para criar uma nova classe no visual studio code, basta selecionar o projeto da API com o botão direito e selecionar a opção New File (Novo Arquivo). Ao ser exibida a caixa de diálogo, selecione Class (Classe) e dê o nome a esta classe de PersonService

O código da classe adicionada ficará semelhante ao código abaixo, portanto, copie e cole em sua classe o código abaixo:

namespace EstudoInjecaoDependencia;

public class PersonService
{
      public string GetPersonName()
    {
        return "você, estudando Injeção de Dependência";
    }
}

No arquivo Program.cs, adicione a linha abaixo, logo acima da linha var app = builder.Build();

builder.Services.AddSingleton<PersonService>();

E por fim, abaixo da instrução app.MapGet("/weatherforecast", () =>... adicione a linha abaixo, que irá realizar o mapeamento de solicitações HTTP GET para a raiz (/) do seu projeto:

app.MapGet("/", 
    (PersonService personService) => 
    {
        return $"Olá {personService.GetPersonName()}!";
    }
);

Salve seus arquivos e pressione F5 para executar a aplicação. Ao executar a mesma, a página padrão do swagger será exibida, mas após o carregamento, vamos para a raiz (/) no endereço, removendo o trecho /swagger/index.html na barra de endereços e pressionando enter. O resultado esperado é termos a apresentação da mensagem, assim como codificamos. Teremos a apresentação como a imagem abaixo:

estudo-injecao-3.png

Injeção de Dependência e Interfaces

Dica: Conceito de Interface: Em .NET Core, uma interface é um tipo de referência que define um contrato que outros tipos devem implementar. Esse contrato especifica os membros que o tipo que implementa deve fornecer, como propriedades, métodos e eventos. Veremos mais sobre os conceitos em nossa futura trilha onde iremos explorar o início da programação assim como a programação orientada a objetos.

Para evitar dependências de uma implementação de serviço específica, você pode configurar um serviço para uma interface específica e depois depender apenas da interface. Essa abordagem oferece flexibilidade para trocar a implementação do serviço, o que torna o código mais testável e mais fácil de manter.

Considere a interface para a classe PersonService.

public interface IPersonService
{
    string GetPersonName();
}

Essa interface define o método único, GetPersonName, que retorna uma string. Esta classe PersonService implementa a interface IPersonService:

internal sealed class PersonService : IPersonService
{
    public string GetPersonName()
    {
        return "você, estudando Injeção de Dependência";
    }
}

Em vez de registrar a classe PersonService diretamente, você pode registrá-la como uma implementação da interface IPersonService:

var builder = WebApplication.CreateBuilder(args);
    
builder.Services.AddSingleton<IPersonService, PersonService>();
var app = builder.Build();

app.MapGet("/", 
    (IPersonService personService) => 
    {
        return $"Olá {personService.GetPersonName()}!";
    }
);
    
app.Run();

O Exemplo deste Program.cs difere do anterior apresentado em dois fatores:

  • A instância PersonService é registrada como uma implementação da interface IPersonService (em vez de registrar diretamente a classe PersonService).

  • A assinatura do delegate agora espera um parâmetro IPersonService em vez de um parâmetro PersonService.

Dica: Pense no IPersonService como um contrato. Ele define os métodos e propriedades que uma implementação deve ter. O delegate deseja uma instância de IPersonService. Ele não se importa com a implementação subjacente, apenas com o fato de a instância ter os métodos e propriedades definidos no contrato.

Alterando nosso código para aplicar a Injeção de Dependência com Interface

Para reproduzirmos a injeção através da Interface, vamos executar os passos abaixo:

  • Em sua solução, crie uma interface IPersonService, assim como criou a classe na parte superior deste artigo.
public interface IPersonService
{
    string GetPersonName();
}
  • Faça a alteração da classe PersonService para o código apresentado abaixo, onde a classe implementa a interface IPersonService criada acima:
internal sealed class PersonService : IPersonService
{
    public string GetPersonName()
    {
        return "você, estudando Injeção de Dependência";
    }
}

Faça as seguintes alterações no arquivo Program.cs.

  • Altere a linha inserida builder.Services.AddSingleton<PersonService>(); pela linha abaixo:
builder.Services.AddSingleton<IPersonService, PersonService>();
  • Altere a linha app.MapGet() inserida pela linha abaixo:
app.MapGet("/", 
    (IPersonService personService) => 
    {
        return $"Olá {personService.GetPersonName()}!";
    }
);
  • Por fim, salve as alterações e execute a aplicação novamente. O resultado esperado deverá ser o mesmo que o obtido anteriormente, mudando apenas a forma de implementação.

Segue imagens da seção Solution Explorer com os arquivos e o resultado esperado:

estudo-injecao-4.png

Imagem com a página inicial do swagger e o retorno do GET na raiz do projeto (/) após alterações.

estudo-injecao-5.png

Program.cs com alterações de Injeção de Dependência

estudo-injecao-6.png

Classe PersonService e interface IPersonService após alteração

Conclusão

Neste artigo conseguimos aplicar a utilização da injeção de dependência no .Net Core. Nos próximos artigos iremos mergulhar um pouco mais a fundo, mas com esta introdução já é possível identificar os ganhos de trabalhar com a Injeção de Dependência.

Se você gostou do conteúdo, deixe um comentário ou uma reação para apoiar o projeto! Compartilhe com alguém e ajude a divulgar!

Até a próxima!

[ ]´s Degas.