Você está utilizando HttpClient da maneira correta?

Alguns problemas não são evidentes

Construir um software que funcione isolado sem realizar integrações com outros sistemas é um fato muito raro. Praticamente todo software realiza integrações com outros componentes, sejam eles internos ou externos. Atualmente, a forma mais popular para promover a integração entre sistemas é o protocolo HTTP, e para que softwares em .NET possam se comunicar através deste protocolo, conhecer a classe HttpClient é obrigatório para o desenvolvimento adequado.

O uso indevido do HttpClient pode gerar exaustão de recursos (principalmente de sockets), pois mesmo que a classe implemente a interface IDisposable, no caso específico do HttpClient, a liberação de recursos pelo método Dispose não acontece para os sockets de conexão TCP. Tal característica é bem documentada pela Microsoft, contudo muitos desenvolvedores acabam realizando implementações como o exemplo abaixo:

public async Task<IEnumerable<SpaceflightNewDTO>> GetUsingAntiPattern()
{
    using var httpClient = new HttpClient();
    var response = await httpClient.GetAsync("https://api.spaceflightnewsapi.net/v3/articles");
    var json = await response.Content.ReadAsStringAsync();
    return JsonConvert.DeserializeObject<IEnumerable<SpaceflightNewDTO>>(json);
}

Embora a utilização do using seja reconhecidamente uma boa prática em casos de implementação de IDisposable, o HttpClient foi planejado para ser utilizado de forma compartilhada, aproveitando ao máximo as conexões já criadas (sockets), mantendo-as em aberto mesmo que o objeto HttpClient seja liberado pela instrução using, sendo um potencial motivo da máquina sofrer com Socket Starvation.

Para mitigar este problema, podemos declarar uma instância de HttpClient como static, ou configurar o contêiner de injeção de dependência para criar a instância como singleton. Essa abordagem garante que teremos uma instância apenas de HttpClient, deixando o gerenciamento de sockets como responsabilidade desta única instância. Contudo, embora seja uma implementação válida, essa não é a melhor alternativa, pois o client não funcionará da forma esperada em caso de alteração do DNS.

O que fazer para solucionar o problema?

No .NET Core 2.1 foi introduzida a classe DefaultHttpClientFactory para construção de instâncias de HttpClient. Essa implementação obedece o contrato IHttpClientFactory e pode ser integrado com o  pacote Microsoft.Extensions.DependencyInjection.

Podemos utilizar o IHttpClientFactory de 4 formas distintas, sendo elas:

  • Basic usage: o IHttpClientFactory é injetado diretamente no construtor, onde é utilizado o método CreateClient para obter uma instância HttpClient;
  • Named Clients: instâncias HttpClient são nomeadas e definidas na configuração do contêiner de injeção de dependências, sendo criadas através de seus alias pelo método CreateClient do IHttpClientFactory;
  • Generated Clients: faz uso do IHttpClientFactory em combinação com bibliotecas de terceiros;
  • Typed Clients: essa abordagem traz consigo o benefício de poder injetar diretamente o HttpClient na classe desejada.

Dentre as abordagens citadas, recomendamos a abordagem de typed clients, pois, conforme mencionado acima, ela possibilita a injeção direta do HttpClient, além de prover os mesmos recursos da Named Clients, sem a necessidade de utilizar strings como chaves, possibilitando o encapsulamento da lógica de consumo dos endpoints em serviços isolados. Entretanto, vale ressaltar que essa abordagem depende da integração com o DI da Microsoft, através do método de extensão AddHttpClient. Basicamente, o seu funcionamento consiste em deixar o contêiner de DI realizar a criação do HttpClient e injetar a instância dentro de uma classe de serviço.

Na prática, precisamos apenas de uma classe que receberá, por injeção de dependência, uma instância HttpClient, como o código abaixo demonstra:

public sealed class CorrectPatternHttpService : ICorrectPatternHttpService
{
    private readonly HttpClient _httpClient;

    public CorrectPatternHttpService(HttpClient httpClient)
    {
        _httpClient = httpClient;
    }

    public async Task<IEnumerable<SpaceflightNewDTO>> GetUsingCorrectPatternAsync()
    {           
        var response = await _httpClient.GetAsync("https://api.spaceflightnewsapi.net/v3/articles");

        var serializer = new JsonSerializer();
        using var stream = await response.Content.ReadAsStreamAsync();
        using var streamReader = new StreamReader(stream);
        using var jsonTextReader = new JsonTextReader(streamReader);
        return serializer.Deserialize<IEnumerable<SpaceflightNewDTO>>(jsonTextReader);
    }
}

Por fim, o código abaixo, demonstra a configuração dentro do contêiner de DI que permite que o IHttpClientFactory faça o trabalho de gerenciar as instâncias de HttpClient:

internal static IServiceCollection AddHttpClients(this IServiceCollection services)
{
    services.AddHttpClient<ICorrectPatternHttpService, CorrectPatternHttpService>();
    return services;
}

Conclusão

A utilização equivocada do HttpClient para realizar integrações entre sistemas via HTTP, pode causar diferentes tipos de problemas e trazer enormes dores de cabeça. Portanto, conhecer a melhor abordagem para a realização de requisições HTTP não é negociável, mas sim imprescindível nos dias de hoje.

Compartilhe este insight:

Comentários

Participe deixando seu comentário sobre este artigo a seguir:

Subscribe
Notify of
guest
0 Comentários
Inline Feedbacks
View all comments

AUTOR

Francisco Schneider
Desenvolvedor especialista em .NET com experiência em aplicações corporativas complexas.

INSIGHTS EXIMIACO

Desenvolvimento de Software

Gestão de times para acelerar entregas e atuar na resolução de problemas complexos.

NOVOS HORIZONTES PARA O SEU NEGÓCIO

Nosso time está preparado para superar junto com você grandes desafios tecnológicos.

Entre em contato e vamos juntos utilizar a tecnologia do jeito certo para gerar mais resultados.

Insights EximiaCo

Confira os conteúdos de negócios e tecnologia desenvolvidos pelos nossos consultores:

Desenvolvimento de Software

A Importância da Proposta de Valor na Modernização de Sistemas Legados

Especialista em Comunicação Digital, UX/UI e Design Thinking
Desenvolvimento de Software

Construindo Produtos Inteligentes, Atraentes e Fáceis de Usar

Especialista em Comunicação Digital, UX/UI e Design Thinking
Desenvolvimento de Software

Como a Proposta de Valor Impacta a Experiência dos Usuários nos Produtos Digitais

Especialista em Comunicação Digital, UX/UI e Design Thinking
EximiaCo 2024 - Todos os direitos reservados
0
Queremos saber a sua opinião, deixe seu comentáriox
()
x
Oferta de pré-venda!

Mentoria em
Arquitetura de Software

Práticas, padrões & técnicas para Arquitetura de Software, de maneira efetiva, com base em cenários reais para profissionais envolvidos no projeto e implantação de software.

Muito obrigado!

Deu tudo certo com seu envio!
Logo entraremos em contato

Você está utilizando HttpClient da maneira correta?

Para se candidatar nesta turma aberta, preencha o formulário a seguir:

Você está utilizando HttpClient da maneira correta?

Para se candidatar nesta turma aberta, preencha o formulário a seguir:

Condição especial de pré-venda: R$ 14.000,00 - contratando a mentoria até até 31/01/2023 e R$ 15.000,00 - contratando a mentoria a partir de 01/02/2023, em até 12x com taxas.

Tenho interesse nessa capacitação

Para solicitar mais informações sobre essa capacitação para a sua empresa, preencha o formulário a seguir:

Tenho interesse em conversar

Se você está querendo gerar resultados através da tecnologia, preencha este formulário que um de nossos consultores entrará em contato com você:

O seu insight foi excluído com sucesso!

O seu insight foi excluído e não está mais disponível.

O seu insight foi salvo com sucesso!

Ele está na fila de espera, aguardando ser revisado para ter sua publicação programada.

Tenho interesse em conversar

Se você está querendo gerar resultados através da tecnologia, preencha este formulário que um de nossos consultores entrará em contato com você:

Tenho interesse nessa solução

Se você está procurando este tipo de solução para o seu negócio, preencha este formulário que um de nossos consultores entrará em contato com você:

Tenho interesse neste serviço

Se você está procurando este tipo de solução para o seu negócio, preencha este formulário que um de nossos consultores entrará em contato com você:

× Precisa de ajuda?