Como usar e como não usar HttpClient em .NET

Neste post, mostramos a abordagem correta para o uso da classe HttpClient. Além disso, destacamos como o uso incorreto dessa feature pode comprometer a performance de um sistema.

Um grande e-commerce, em um passado não muito distante, passava por momentos de instabilidade que ocorriam de forma intermitente.

A solução de APM já monitorava, de maneira satisfatória, o nível de operação do GC e o volume de alocação das CPUs. Entretanto, não percebíamos nada de estranho nesses indicadores. Nossas suspeitas recaíram sobre a rede.

Utilizando o perfmon, constatamos forte crescimento no número de Conexões estabelecidas e de Conexões ativas (ambos recursos do sistema operacional). Na época, pareceu sensato começar as investigações em pontos do sistema que “batiam” em serviços externos.

Examinando o código, sem muitas surpresas, identificamos utilização ineficiente da classe HttpClient.

Como NÃO usar HttpClient

Embora não recomendada, a utilização de HttpClient como indicado no código abaixo é bastante comum:

public class Versao1
{
    private readonly string _baseUrl;

    public Versao1(string baseUrl)
    {
        _baseUrl = baseUrl;
    }

    public string Obter(string query)
    {
        string retorno;

        using (HttpClient client = new HttpClient())
        {
            client.BaseAddress = new Uri(_baseUrl);
            .
            .
            .
        }

        return retorno;
    }
}

No código acima, toda vez que o método Obter() é chamado uma instância de HttpClient é criada. Por estar em um bloco using, esta instância é descartada (pelo menos é o que esperamos).

O problema é que essa abordagem contraria a recomendação de uso da própria Microsoft.

HttpClient destina-se a ser instanciado uma vez e reutilizadas em toda a vida útil de um aplicativo. Criando uma instância de uma classe HttpClient para cada solicitação irá esgotar o número de soquetes disponíveis com cargas pesadas. Isso resultará em erros SocketException.

Isso acontece porque, embora HttpClient implemente a interface IDisposable (por favor, leia esse post para entender mais sobre a tratativa de recursos não gerenciados), “por baixo do capô”, ele mantem estado compartilhado e thread safe entre diversas instâncias.

O vídeo abaixo mostra o impacto dessa abordagem inicando número de conexões realizadas.

Como usar HttpClient

É boa prática, mais do que recomendada, indicada pela da Microsoft, manter uma única de HttpClient uma instância, em uma variável estática, para toda a aplicaçãoModernamente, recomenda-se a utilização de IHttpClientFactory.

public class Versao2
{
    private static readonly HttpClient HttpClient = new HttpClient();

    public async string Obter(string url)
    {
        var resultado = await HttpClient.GetAsync(url);
        if (resultado.StatusCode != System.Net.HttpStatusCode.OK)
            throw new HttpRequestException($"{resultado.StatusCode}-{resultado.RequestMessage}");

        var retorno = await resultado.Content.ReadAsStringAsync();
        return retorno;
    }
}

Como a Microsoft descata, não preciamos nos preocupar com requisições de conexões concorrentes.

Cada instância de HttpClient seu próprio pool de conexões, isolando suas requisições.

No vídeo que segue, vemos o impacto dessa mudança simples no consumo de recursos não gerenciados do sistema operacional.

Concluindo

Há três ofensores comuns para performance: Rede, Disco e GC. Entretanto, frequentemente, problemas ocorrem devido a esgotamento de outros recursos do sistema operacional.

Nesse post, mostramos que mudanças simples do código permitem grande melhoria para as aplicações e podem diminuir instabilidade em nossas aplicações.

O erro que apresentamos aqui é resultado de uma má prática, extremamente comum, mesmo claramente contraindicada na documentação. Isso só reforça a nossa recomendação para que todos se aprofundem um pouco sobre o funcionamento das features que utilizam ANTES de colocá-las em produção.

E você, já teve problemas com HttpClient?

Compartilhe este insight:

Comentários

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

Subscribe
Notify of
guest
12 Comentários
Oldest
Newest Most Voted
Inline Feedbacks
View all comments
Flavio
Flavio
4 anos atrás

Ops acho que usei da forma errada muitas vezes =/

Fábio Lira
Fábio Lira
4 anos atrás

Já vou alterar o meu, obrigado pela excelente dica

Wesley
Wesley
4 anos atrás

Passamos pelo mesmo problema aqui, identificamos centenas de conexões aberta com status Wait usando o nettop (mesmo sem nenhum acesso nas aplicações).
Após alterar para utilizar IHttpClientFactory ou HttpClient estático diminui e muito!

Ricardo Bomfim
Ricardo Bomfim
4 anos atrás

Só há um detalhe sobre usar um singleton do Httpclient, ele não respeita o ttl do dns, esse foi um dos motivos da equipe do aspnetcore ter implementado o IHttpClientFactory

Eduardo Spaki
Eduardo Spaki
4 anos atrás

como gerenciar alteração de headers em comunicações concorrentes nesse cenários?

Alisson Sena
Alisson Sena
4 anos atrás

Tenho utilizado o Refit (https://github.com/reactiveui/refit) para as requisições HttpClient e está funcionando bem.

Tiago Tartari
Tiago Tartari
4 anos atrás

legal, esse eu não conhecia. como está a utilização dele?

Anderson
Anderson
4 anos atrás

Ponto de atenção com operação bloqueante:

HttpClient.GetAsync(url).Result;

Nelson Junior
Nelson Junior
4 anos atrás

Eu discordo do uso de .Result. Pode causar deadlock na operação.

Uma lib que eu tenho usado, inclusive ajuda muito em testes unitários é o https://flurl.dev/

Elemar Júnior
Elemar Júnior
4 anos atrás

Você está certo. A versão desse post em Espanhol já resolve isso.

Tiago Tartari
Tiago Tartari
4 anos atrás

Anderson,
Tudo certo? Desculpe a demora pra responder.

Você tem toda razão!
Foi um descuido da minha parte!!! Fiz a correção no POST.

; )

Júlio Costa
Júlio Costa
4 anos atrás

Caramba, usei errado também, obrigado pelo excelente artigo!

AUTOR

Tiago Tartari
Especialista em SRE, monitoramento, arquitetura de software, processos de due diligence em aquisições e fusões e Microsoft MVP

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:

Arquivo

Pós-pandemia, trabalho remoto e a retenção dos profissionais de TI

CTO Consulting e Especialista em Execução em TI
EximiaCo 2024 - Todos os direitos reservados
12
0
Queremos saber a sua opinião, deixe seu comentáriox
()
x

Muito obrigado!

Deu tudo certo com seu envio!
Logo entraremos em contato

Como usar e como não usar HttpClient em .NET

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

Como usar e como não usar HttpClient em .NET

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?