ASP.NET Core - 5 dicas para melhorar a sua API
 Hoje veremos 5 dicas para melhorar a sua API ASP .NET Core.


A seguir vou apresentar 5 recursos que se aplicados de forma correta vão melhorar a sua API em diversos aspectos. Essas dicas foram compiladas em diversas fontes na web que são citadas nas referências do artigo.
 


 

1- Realizar o tratamento global das exceções
 

Ao invés de espalhar por toda sua API um monte de blocos try-catch lidar com erros inesperados uma forma mais elegante é criar um middleware que trata as exceções de forma global.

 

Um Middleware é um software que é montado em um pipeline de aplicativo para lidar com solicitações e respostas onde cada componente escolhe se a solicitação deve ser passada para o próximo componente no pipeline e que pode executar o trabalho antes e depois do próximo componente no pipeline.

 

Se você não sabe como criar um middleware para tratamento de exceções segue uma implementação padrão que é funcional que você pode ajustar ao seu cenário:

 

using Microsoft.AspNetCore.Mvc;
using System.Net;
using System.Text.Json;

namespace ApiDicas.Middlewares;

public class MiddlewareException
{
    private readonly RequestDelegate next;
    private readonly IHttpContextAccessor accessor;
    private readonly ILogger<MiddlewareException> logger;

    public MiddlewareException(RequestDelegate next, IHttpContextAccessor accessor,
        ILogger<MiddlewareException> logger)
    {
        this.next = next;
        this.logger = logger;
        this.accessor = accessor;
    }

    public async Task Invoke(HttpContext context)
    {
        try
        {
            await next.Invoke(context);
        }
        catch (Exception ex)
        {
            logger.LogError(ex, $"An error was ocurred during the process. Trace Identifier:
{accessor.HttpContext.TraceIdentifier}.");

            await HandleExceptionMessageAsync(accessor.HttpContext).ConfigureAwait(false);
        }
    }

    private static Task HandleExceptionMessageAsync(HttpContext context)
    {
        string response = JsonSerializer.Serialize(new ValidationProblemDetails()
        {
            Title = "An error was occurred.",
            Status = (int)HttpStatusCode.InternalServerError,
            Instance = context.Request.Path,
        });

        context.Response.ContentType = "application/json";
        context.Response.StatusCode = (int)HttpStatusCode.InternalServerError;

        return context.Response.WriteAsync(response);
    }
}

 

Para usar basta definir o código em destaque na classe Program:

 

using ApiDicas.Middlewares;

var builder = WebApplication.CreateBuilder(args);

// Add services to the container.
builder.Services.AddControllers();
builder.Services.AddEndpointsApiExplorer();
builder.Services.AddSwaggerGen();

builder.Services.AddSingleton<IHttpContextAccessor, HttpContextAccessor>();

var app = builder.Build();

// Configure the HTTP request pipeline.
if (app.Environment.IsDevelopment())
{
    app.UseSwagger();
    app.UseSwaggerUI();
}

app.UseHttpsRedirection();
app.UseAuthorization();
app.UseMiddleware<MiddlewareException>();
app.MapControllers();
app.Run();

 

2- Acesse as informações HTTP atrás de um proxy.

Quando as solicitações HTTPS são enviadas via proxy sobre HTTP, o esquema original (HTTPS) é perdido e deve ser encaminhado em um cabeçalho.

 

Como um aplicativo recebe uma solicitação do proxy e não sua verdadeira fonte na Internet ou na rede corporativa, o endereço IP do cliente de origem também deve ser encaminhado em um cabeçalho.

Isso acontece mesmo em ambientes como, por exemplo, quando estamos tentando capturar o endereço IP por meio de HttpContext.Connection.RemoteIpAddress em uma aplicação container docker.

Para obter mais informações, você pode acessar o link: Configurar ASP.NET Core para trabalhar com servidores proxy e balanceadores de carga

Uma forma de contornar este problema é definir o serviço para o middleware ForwardedHeaders conforme orienta o link acima:

 

builder.Services.Configure<ForwardedHeadersOptions>(options =>
{
    options.ForwardedHeaders =
        ForwardedHeaders.XForwardedFor | ForwardedHeaders.XForwardedProto;
});

Código para habilitar  o middleware no arquivo Program:

app.UseForwardedHeaders();

Depois disso, ao invés de obter o IP do proxy, ele terá o cabeçalho X-Forwarded-For quando a requisição for encaminhada. Com essas configurações, o aplicativo substituirá pelo encaminhamento de IP no cabeçalho.

3- Usar a interface IHttpContextAccessor ao invés do context Http

A interface IHttpContextAccessor é usada  para acessar o contexto HTTP em .NET, e por utilizar injeção de dependência, é extremamente útil quando precisamos de alguma informação em camadas de serviço.

Assim aplicativos ASP.NET Core podem acessar o HttpContext por meio da interface IHttpContextAccessor e sua implementação padrão HttpContextAccessor. Só é necessário usar IHttpContextAccessor quando você precisa acessar o HttpContext dentro de um serviço.

Para isso primeiro registre o serviço no container DI:

builder.Services.AddSingleton<IHttpContextAccessor, HttpContextAccessor>();

A seguir injete onde precisar usar e seja feliz:

private readonly IHttpContextAccessor _contextAccessor;
private readonly ILogger<WeatherForecastController> _logger;

public WeatherForecastController(ILogger<WeatherForecastController> logger,
                                  IHttpContextAccessor contextAccessor)
{
   _logger = logger;
   _contextAccessor = contextAccessor;
}

4- Implemente o tratamento de erros usando a classe ProblemDetails

Um RFC chamada Problem Details(RFC7807) padroniza como um erro em uma API deve ser respondido para o cliente. Se você usa a validação Fluent, deve ter notado que a resposta está dentro desse padrão.

Ocorre que a ASP .NET Core oferece a classe ProblemDetails que também implementa esse padrão e que você pode usar no seu projeto. Você pode encontrar a documentação aqui: Classe ProblemDetails.

A seguir temos um exemplo de um corpo de resposta formatado como o objeto ProblemDetails que mostra o resultado da busca de um produto que não foi encontrado:

Como podemos ver nos cabeçalhos de resposta, o objeto JSON de detalhes do problema é do tipo “application/problem + json”. Conforme especifica a documentação, ela contém os seguintes membros:

- Type – [string] – referência de URI para identificar o tipo de problema
- Títle – [string] – um breve resumo do problema legível por humanos
- Status – [número] – o código de status HTTP gerado na ocorrência do problema
- Detail – [string] – uma explicação legível para o que exatamente aconteceu
- Instance – [string] – referência URI da ocorrência

Como boas práticas de implementação, é sempre importante seguir os padrões de algumas RFCs, pois proporciona um melhor design.

5-  Utilize o Logging com cuidado

O HTTP Logging é um middleware que registra informações sobre solicitações e respostas HTTP.  O registro em log HTTP fornece logs de:

  • Informações de solicitação HTTP
  • Propriedades comuns
  • Cabeçalhos
  • Corpo
  • Informações de resposta HTTP

Por padrão, o registro em log HTTP registra propriedades comuns, como caminho, código de status e cabeçalhos, para solicitações e respostas. Adicione a seguinte linha ao arquivo appsettings.Development.json no nível "LogLevel"  para que os logs HTTP sejam exibidos: 

"Microsoft.AspNetCore.HttpLogging.HttpLoggingMiddleware": "Information"

Esse middleware é extremamente útil para visibilidade usando logs, mas é extremamente importante manter duas coisas em mente.

  1. Avalie seu uso para dados sensíveis
  2. Atente para o fato de que esse middleware pode reduzir o desempenho do aplicativo, principalmente ao registrar os corpos de requisição e resposta, por isso é importante estar atento a sua configuração.

Para habilitar o middleware use o código: app.UseHttpLogging();

Você pode encontrar detalhes da utilização do logging na documentação: HTTP Logging in ASP.NET Core

E estamos conversados...

"Porque a loucura de Deus é mais sábia do que os homens; e a fraqueza de Deus é mais forte do que os homens."
1 Coríntios 1:25

Porque um menino nos nasceu, um filho se nos deu, e o principado está sobre os seus ombros, e se chamará o seu nome: Maravilhoso, Conselheiro, Deus Forte, Pai da Eternidade, Príncipe da Paz.

Isaías 9:6
Porque um menino nos nasceu, um filho se nos deu, e o principado está sobre os seus ombros, e se chamará o seu nome: Maravilhoso, Conselheiro, Deus Forte, Pai da Eternidade, Príncipe da Paz.

Isaías 9:6

Referências:


José Carlos Macoratti