.NET Core — Dependency Injection
Exemplificando Singleton / Scoped / Transient
Olá tudo bem? Sabemos que por padrão o .NET Core trás uma interface que injeta das dependências de forma simples e amigável. No entanto, muitas vezes, não sabemos como usar de forma correta. Neste post, vou tentar exemplificar o uso dos 3 tipos de registro de dependências: Singleton, Scoped e Transient.
Vida útil de um serviço
Quando registramos um serviço, somos nós quem decidimos qual será a vida útil dele. Definir a vida útil, quer dizer que saberemos quantas vezes um componente é instanciado e se um componente é compartilhado. E no .NET Core existem 3 opções para isso:
Singleton
Significa que apenas uma única instância será criada. Essa instância é compartilhada entre todos os componentes que exigem isso. A mesma instância é, portanto, usada sempre.
Scoped
Uma instância é criada uma vez por escopo. Um escopo é criado em cada solicitação para o aplicativo (cada pedido é um escopo), portanto, todos os componentes registrados como scoped serão criados uma vez por solicitação.
Transient
Os componentes são criados toda vez que são solicitados e nunca são compartilhados.
IServiceColletion
IServiceColletion é interface responsável por registrar nossos componentes/serviços. Então a partir dela vamos iniciar nossa demo.
Vamos criar um projeto vazio do tipo ASP Net Core Web Application. No projeto vou criar a seguinte estrutura:
Todas as interfaces terão um método que retornarão um Guid. O código fonte estará no final do post.
Na classe Startup, vamos registrar dessa forma:
public void ConfigureServices(IServiceCollection services)
{
services.AddScoped<IScopedService, ScopedService>();
services.AddSingleton<ISingletonService, SingletonService>();
services.AddTransient<ITransientService, TransientService>();
}
Na DemoController vamos injetar as interfaces no construtor e criar métodos de Get para cada um dos serviços. Mas antes, vamos também criar uma cópia de cada uma das interfaces, por exemplo:
private readonly IScopedService _scopedService_1;
private readonly IScopedService _scopedService_2;private readonly ISingletonService _singletonService_1;
private readonly ISingletonService _singletonService_2;private readonly ITransientService _transientService_1;
private readonly ITransientService _transientService_2;
Desta forma, vamos ver o resultado quando chamamos as 2 instâncias mais de uma vez.
Exibindo resultados
Enfim os resultados quando chamamos 2 vezes a API.
Scoped:
Nos 2 casos chamando a API, a instância 2 reutilizou o que a instância 1 tinha criado.
Singleton:
Uma vez criada a instância 1, todo o resto vai reutilizar. Não houve uma nova criação de valores na segunda chamada da API.
Transient:
Por fim, vemos que nas duas chamadas à API, cada instância criou seus próprios valores.
Conclusão
Já sabe qual usar? Vamos a alguns exemplos:
- Scoped: Se quiser manter o estado do serviço em um request. Eles só irão mudar sempre quando fizer um novo request.
- Singleton: Onde você precisa reutilizar o serviço em várias pontas de sua aplicação como por exemplo: configurações do aplicativo ou parâmetros, serviço de log, armazenamento em cache de dados.
- Transient: Temporário, passageiro como tradução literal. Será criada uma nova instância do objeto toda vez que fizer uma requisição. Mas, uma vez que eles são criados, eles usarão mais memória e recursos, e podem ter o impacto negativo no desempenho. Então use para o serviço leve com pouco ou nenhum estado.