.Net Core 8 - Parte 6: Entendendo a Injeção de Dependência, criando um aplicativo, registrando e consumindo um serviço
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
.
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:
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:
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
eeventos
. 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 interfaceIPersonService
(em vez de registrar diretamente a classePersonService
). -
A assinatura do
delegate
agora espera um parâmetroIPersonService
em vez de um parâmetroPersonService
.
Dica: Pense no
IPersonService
como um contrato. Ele define osmétodos
epropriedades
que uma implementação deve ter. Odelegate
deseja uma instância deIPersonService
. 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 interfaceIPersonService
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:
Imagem com a página inicial do
swagger
e o retorno do GET na raiz do projeto(/)
após alterações.
Program.cs
com alterações de Injeção de Dependência
Classe
PersonService
e interfaceIPersonService
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.