ASP.NET Core - Dicas para ter uma Web API robusta
![]() |
Neste artigo veremos algumas dicas para criar um código bem organizado e de fácil manutenção que irá melhorar a qualidade da sua API. |
Injeção de dependência
Ao criar sua Web API implemente a DI e a IoC para desacoplar dependências e promover testabilidade e flexibilidade.
Para isso use um contêiner DI, como o contêiner DI .NET integrado ou uma framework de terceiros como Autofac ou Ninject.
Na plataforma .NET podemos registrar os serviços no contêiner DI :
builder.Services.AddDbContext<AppDbContext>(options => options.UseMySql(mySqlConnection, ServerVersion.AutoDetect(mySqlConnection))); builder.Services.AddScoped<IProdutoRepository, ProdutoRepository>(); builder.Services.AddScoped<IProdutoService, ProdutoService>(); |
Exemplo de Injeção de dependência do serviço no controlador :
[Route("[controller]")] [ApiController] public class ProdutosController : ControllerBase { private readonly IProdutoService _produtoService; public ProdutosController(IProdutoService produtoService) { _produtoService = produtoService; } ... } |
Exemplo de Injeção de dependência do Repositório no serviço:
public
class
ProdutoService :
IProdutoService { private readonly IProdutoRepository _produtoRepository; public ProdutoService(IProdutoRepository produtoRepository) { _produtoRepository = produtoRepository } ... } |
Exemplo de Injeção de dependencia do contexto no repositório :
public
class
ProdutoRepository :
IProdutoRepository { public ProdutoRepository(AppDbContext context) : base(context) {} ... } |
Essa estrutura é conhecida como "Repository Pattern" (Padrão Repositório) e "Service Layer" (Camada de Serviço).
A ideia é dividir a responsabilidade da manipulação de dados (através do repositório) e a lógica de negócios (através do serviço), o que pode levar a uma melhor separação de preocupações e facilitar a manutenção do código.
Programação assíncrona
Aproveite o recurso async e o await para escrever código assíncrono que melhore a capacidade de resposta e a escalabilidade da sua API Web.
Utilize versões assíncronas de métodos quando disponíveis, como usar operações assíncronas de banco de dados ou chamadas HTTP assíncronas.
Exemplo:
[HttpGet("pagination")] public async Task<ActionResult<IEnumerable<ProdutoDTO>>> Get([FromQuery]ProdutosParameters produtosParameters CancellationToken cancellationToken ) { var produtos = await _uof.ProdutoRepository.GetProdutosAsync(produtosParameters, cancellationToken); return ObterProdutos(produtos); } |
Cache
Incorpore mecanismos de cache, como cache na memória ou cache distribuído, para melhorar o desempenho e reduzir chamadas desnecessárias a recursos externos.
O uso de caching em Web APIs ASP.NET Core é uma prática comum para melhorar o desempenho e reduzir a carga no servidor, especialmente quando os dados têm uma taxa de alteração relativamente baixa ou quando é aceitável ter uma pequena latência nos dados. O ASP.NET Core fornece suporte integrado para caching.
O ASP.NET Core possui um middleware de caching de resposta integrado que permite armazenar em cache as respostas HTTP completas :
app.UseResponseCaching(); |
Você pode aplicar atributos [ResponseCache] em ações do controlador para controlar o comportamento do cache em nível de ação.
[HttpGet("{id}")]
[ResponseCache(Duration = 60)]
public IActionResult GetProduto(int id)
{
// Retorna o produto do cache ou do banco de dados
// ...
}
|
A ASP.NET Core também fornece uma implementação de cache em memória que você pode usar para armazenar dados em cache temporariamente. Isso pode ser especialmente útil quando você precisa armazenar em cache dados que são caros de calcular ou recuperar.
public class MeuServico
{
private readonly IMemoryCache _memoryCache;
public MeuServico(IMemoryCache memoryCache)
{
_memoryCache = memoryCache;
}
public async Task<object> ObterDadosCacheados()
{
if (!_memoryCache.TryGetValue("ChaveDoCache", out var dados))
{
// Dados não estão no cache, recupere e armazene em cache
dados = await ObterDadosDoBancoDeDados();
var cacheEntryOptions = new MemoryCacheEntryOptions
{
// Define o tempo de expiração do cache
AbsoluteExpirationRelativeToNow = TimeSpan.FromMinutes(10),
// Define o tempo de expiração do cache após o último acesso
SlidingExpiration = TimeSpan.FromMinutes(5) };
_memoryCache.Set("ChaveDoCache", dados, cacheEntryOptions);
}
return dados;
}
private async Task<object> ObterDadosDoBancoDeDados()
{
// Lógica para recuperar dados do banco de dados
// Exemplo fictício, substitua pela sua lógica real
return new object();
}
}
|
Certifique-se de configurar o serviço de cache em memória no método :
builder.Services.AddMemoryCache();
Se você estiver executando sua aplicação em um ambiente distribuído (por exemplo, em uma configuração de balanceamento de carga), considerar um cache distribuído como o Redis pode ser uma opção.
Isso permite compartilhar o cache entre várias instâncias da aplicação.
...
builder.Services.AddDistributedRedisCache(options =>
{
options.Configuration = "sua_string_de_conexao_redis";
options.InstanceName = "NomeDaInstanciaDoCache";
});
|
E, em seguida, você pode usar o IDistributedCache nos seus serviços e controladores da mesma maneira que você usaria o IMemoryCache.
Tratamento do Cross-Cutting
O termo "cross-cutting" refere-se a preocupações que afetam várias partes de uma aplicação, cortando através de diferentes módulos ou camadas. Em uma aplicação ASP.NET Core, o "cross-cutting concern" geralmente se refere a funcionalidades ou lógicas que não se encaixam perfeitamente em uma única camada ou módulo, mas que são relevantes para vários componentes. Exemplos:
IActionFilter
,
IExceptionFilter
), além
de middlewares.A ASP.NET Core utiliza um pipeline de middleware para processar solicitações HTTP. Middlewares são componentes que podem executar lógica antes ou depois que a solicitação atinge o controlador. Você pode criar middlewares para lidar com preocupações transversais, como logging, compressão, tratamento de erros, etc.
Você pode criar um middleware personalizado ou aproveitar os componentes de middleware existentes disponíveis no ecossistema ASP.NET Core.
Exemplo:
// ...
app.UseAuthentication();
app.UseRouting();
app.UseAuthorization();
// middleware para logar o tratamento de exceção etc.
app.UseCustomLoggingMiddleware();
app.UseExceptionHandlingMiddleware();
app.UseEndpoints(endpoints =>
{
endpoints.MapControllers();
});
// ...
|
Essas são algumas dicas que se aplicadas de forma correta irão tornar a sua API mais robusta e fácil de testar e manter.
E estamos
conversados...
"Na verdade, na verdade vos digo que quem ouve a minha palavra, e crê naquele
que me enviou, tem a vida eterna, e não entrará em condenação, mas passou da
morte para a vida."
João
5:24
Referências:
C# - Tasks x Threads. Qual a diferença
DateTime - Macoratti.net
Null o que é isso ? - Macoratti.net
Formatação de data e hora para uma cultura ...
C# - Calculando a diferença entre duas datas
NET - Padrão de Projeto - Null Object Pattern
C# - Fundamentos : Definindo DateTime como Null ...
C# - Os tipos Nullable (Tipos Anuláveis)