O HttpClient e o HttpClientHandler precisam ser descartados entre solicitações?

334

System.Net.Http.HttpClient e System.Net.Http.HttpClientHandler no .NET Framework 4.5 implementam IDisposable (via System.Net.Http.HttpMessageInvoker ).

A usingdocumentação da declaração diz:

Como regra, quando você usa um objeto IDisposable, você deve declarar e instancia-lo em uma instrução using.

Esta resposta usa este padrão:

var baseAddress = new Uri("http://example.com");
var cookieContainer = new CookieContainer();
using (var handler = new HttpClientHandler() { CookieContainer = cookieContainer })
using (var client = new HttpClient(handler) { BaseAddress = baseAddress })
{
    var content = new FormUrlEncodedContent(new[]
    {
        new KeyValuePair<string, string>("foo", "bar"),
        new KeyValuePair<string, string>("baz", "bazinga"),
    });
    cookieContainer.Add(baseAddress, new Cookie("CookieName", "cookie_value"));
    var result = client.PostAsync("/test", content).Result;
    result.EnsureSuccessStatusCode();
}

Mas os exemplos mais visíveis da Microsoft não chamam Dispose()explícita ou implicitamente. Por exemplo:

Nos comentários do anúncio , alguém perguntou ao funcionário da Microsoft:

Depois de verificar suas amostras, vi que você não executou a ação de disposição na instância HttpClient. Eu usei todas as instâncias do HttpClient com a declaração using no meu aplicativo e achei que era o caminho certo, já que o HttpClient implementa a interface IDisposable. Estou no caminho certo?

Sua resposta foi:

Em geral, isso está correto, embora você tenha que ter cuidado com "using" e assíncrono, pois eles realmente não se misturam no .Net 4. No .Net 4.5, você pode usar "waitit" dentro de uma instrução "using".

Aliás, você pode reutilizar o mesmo HttpClient quantas vezes quiser [normalmente], assim normalmente você não os cria / descarta o tempo todo.

O segundo parágrafo é supérfluo para essa pergunta, que não se preocupa com quantas vezes você pode usar uma instância HttpClient, mas se é necessário descartá-la depois que você não precisar mais dela.

(Atualização: na verdade, o segundo parágrafo é a chave da resposta, conforme fornecido abaixo pelo @DPeden.)

Então, minhas perguntas são:

  1. É necessária, dada a implementação atual (.NET Framework 4.5), chamar Dispose () nas instâncias HttpClient e HttpClientHandler? Esclarecimento: por "necessário", quero dizer se existem consequências negativas por não descartar, como vazamento de recursos ou riscos de corrupção de dados.

  2. Se não for necessário, seria uma "boa prática", já que eles implementam IDisposable?

  3. Se for necessário (ou recomendado), esse código mencionado acima está implementando-o com segurança (no .NET Framework 4.5)?

  4. Se essas classes não exigem a chamada Dispose (), por que elas foram implementadas como IDisposable?

  5. Se eles exigirem ou se for uma prática recomendada, os exemplos da Microsoft são enganosos ou inseguros?

Fernando Correia
fonte
2
@Damien_The_Unbeliever, obrigado pelo seu feedback. Você tem alguma sugestão de como eu poderia esclarecer a questão? Quero saber se isso pode levar a problemas geralmente associados à não eliminação de recursos, como vazamento de recursos e corrupção de dados.
Fernando Correia
9
@Damien_The_Unbeliever: Não é verdade. Em particular, os gravadores de fluxo devem ser dispostos para ter um comportamento correto.
Stephen Cleary
1
@StephenCleary - em que aspectos você está pensando? Certamente, você pode chamar Flushum após cada gravação e, além do inconveniente de continuar mantendo os recursos subjacentes por mais tempo do que o necessário, o que não ocorrerá necessário para o "comportamento correto"?
Damien_The_Unbeliever
1
Isso está totalmente errado: "Como regra, quando você usa um objeto IDisposable, você deve declarar e instanciar em uma instrução using". Eu lia a documentação da classe que implementa o IDisposable sempre antes de decidir se devo usá-lo. Como o autor das bibliotecas em que eu implemento o IDisposable, porque preciso liberar recursos não gerenciados, ficaria horrorizado se os consumidores criados descartassem uma instância a cada vez, em vez de reutilizar uma instância existente. Isso não quer dizer que não descarte instância, eventualmente ..
markmnl
1
Eu enviei um PR para a Microsoft para atualizar seus documentos: github.com/dotnet/docs/pull/2470
markmnl

Respostas:

259

O consenso geral é que você não precisa (não deve) descartar o HttpClient.

Muitas pessoas que estão intimamente envolvidas na maneira como funciona afirmam isso.

Consulte a publicação no blog de Darrel Miller e uma publicação relacionada ao SO: o rastreamento do HttpClient resulta em vazamento de memória para referência.

Eu também sugiro fortemente que você leia o capítulo HttpClient em Designing Evolvable Web APIs with ASP.NET para um contexto sobre o que está acontecendo sob o capô, particularmente a seção "Ciclo de vida" citada aqui:

Embora o HttpClient implemente indiretamente a interface IDisposable, o uso padrão do HttpClient não é descartá-lo após cada solicitação. O objeto HttpClient deve permanecer durante o tempo que seu aplicativo precisar fazer solicitações HTTP. A existência de um objeto em várias solicitações permite um local para a configuração de DefaultRequestHeaders e impede que você precise especificar novamente coisas como CredentialCache e CookieContainer em cada solicitação, conforme necessário com o HttpWebRequest.

Ou até mesmo abra o DotPeek.

David Peden
fonte
64
Para esclarecer sua resposta, seria correto dizer que "você não precisa descartar o HttpClient SE PRECISAR DA INSTÂNCIA PARA REUTILIZÁ-LO MAIS TARDE"? Por exemplo, se um método for chamado repetidamente e criar uma nova instância HttpClient (mesmo que na maioria dos casos não seja o padrão recomendado), ainda assim seria correto dizer que esse método não deve descartar a instância (que não será reutilizada)? Isso pode levar a milhares de instâncias não dispostas. Em outras palavras, você deve tentar reutilizar as instâncias, mas se não as reutilizar, é melhor descartá-las (para liberar as conexões)?
Fernando Correia
8
Eu acho que a resposta compreensivelmente frustrante, mas correta, é que depende. Se eu precisasse dar conselhos gerais que funcionavam na maioria dos casos (nunca digo todos), sugiro que você use um contêiner de IoC e registre uma instância do HttpClient como um singleton. O tempo de vida da instância seria então definido como o tempo de vida do contêiner. Isso pode ter um escopo definido no nível do aplicativo ou talvez por solicitação em um aplicativo Web.
precisa
25
@FernandoCorreia Yes. Se, por algum motivo, você criar e destruir repetidamente instâncias HttpClient, então sim, você deve descartá-lo. Não estou sugerindo ignorar a interface IDisposable, apenas tentando incentivar as pessoas a reutilizarem instâncias.
Darrel Miller
20
Apenas para adicionar mais credibilidade a essa resposta, falei com a equipe do HttpClient hoje e eles confirmaram que o HttpClient não foi projetado para ser usado por solicitação. Uma instância do HttpClient deve ser mantida ativa enquanto um aplicativo cliente continua a interagir com um host específico.
Darrel Miller
19
@DavidPeden Registrar o HttpClient como um singleton parece perigoso para mim porque é mutável. Por exemplo, todos os que estão atribuindo à Timeoutpropriedade não deveriam pisar um no outro?
Jon-Eric
47

As respostas atuais são um pouco confusas e enganosas, e estão faltando algumas implicações importantes do DNS. Vou tentar resumir onde as coisas estão claramente.

  1. De um modo geral, a maioria dos IDisposableobjetos deve ser descartada idealmente quando você terminar com eles , especialmente aqueles que possuem recursos de SO nomeado / compartilhado . HttpClientnão é uma exceção, pois, como aponta Darrel Miller , ele aloca tokens de cancelamento e os organismos de solicitação / resposta podem ser fluxos não gerenciados.
  2. No entanto, a melhor prática para o HttpClient diz que você deve criar uma instância e reutilizá-la o máximo possível (usando seus membros seguros para threads em cenários com vários threads). Portanto, na maioria dos cenários, você nunca descartará isso simplesmente porque precisará disso o tempo todo .
  3. O problema de reutilizar o mesmo HttpClient "para sempre" é que a conexão HTTP subjacente pode permanecer aberta contra o IP originalmente resolvido pelo DNS, independentemente das alterações no DNS . Isso pode ser um problema em cenários como implantação azul / verde e failover baseado em DNS . Existem várias abordagens para lidar com esse problema, a mais confiável envolvendo o servidor enviando um Connection:closecabeçalho após a alteração do DNS. Outra possibilidade envolve reciclar HttpClientno lado do cliente, periodicamente ou através de algum mecanismo que aprenda sobre a alteração do DNS. Consulte https://github.com/dotnet/corefx/issues/11224 para obter mais informações (sugiro que leia com atenção antes de usar cegamente o código sugerido na postagem do blog vinculada).
Ohad Schneider
fonte
I eliminá-lo o tempo todo como eu não posso mudar proxy em uma instância;)
ed22
Se você precisar descartar o HttpClient por qualquer motivo, mantenha uma instância estática do HttpMessageHandler por perto, pois o descarte é realmente a causa dos problemas atribuídos ao descarte do HttpClient. O HttpClient possui uma sobrecarga de construtor que permite especificar que o manipulador fornecido não deve ser descartado; nesse caso, você pode reutilizar o HttpMessageHandler com outras instâncias do HttpClient.
Tom Lint
Você deve manter seu HttpClient, mas pode usar algo como System.Net.ServicePointManager.DnsRefreshTimeout = 3000; Isso é útil, por exemplo, se você estiver em um dispositivo móvel que a qualquer momento possa alternar entre wifi e 4G.
Johan Franzén
18

No meu entender, a chamada Dispose()é necessária apenas quando estiver bloqueando os recursos necessários mais tarde (como uma conexão específica). É sempre recomendável liberar recursos que você não está mais usando, mesmo que não precise mais deles, simplesmente porque geralmente você não deve se apegar a recursos que não está usando (trocadilhos).

O exemplo da Microsoft não está incorreto, necessariamente. Todos os recursos utilizados serão liberados quando o aplicativo sair. E no caso desse exemplo, isso acontece quase imediatamente após o término do HttpClientuso. Em casos semelhantes, chamar explicitamente Dispose()é um tanto supérfluo.

Mas, em geral, quando uma classe é implementada IDisposable, o entendimento é que você deve ter Dispose()suas instâncias assim que estiver totalmente pronto e apto. Eu diria que isso é particularmente verdadeiro em casos como os HttpClientem que não está explicitamente documentado se os recursos ou conexões estão sendo mantidos / abertos. No caso em que a conexão será reutilizada novamente [em breve], convém renunciar Dipose()a ela - você não está "totalmente pronto" nesse caso.

Consulte também: Método IDisposable.Dispose e Quando chamar Dispose

svidgen
fonte
7
É como se alguém trouxesse uma banana para sua casa, a come e está de pé com a casca. O que eles devem fazer com a casca? ... Se eles estiverem saindo pela porta, deixe-os ir. Se eles estiverem por aí, faça-os jogá-lo no lixo para que não cheire mal.
svidgen
apenas para esclarecer esta resposta, você está dizendo: "não é necessário descartar se o programa terminará logo após o uso"? E que você deve descartar se espera-se que o programa continue por algum tempo fazendo outras coisas?
Fernando Correia
@FernandoCorreia Sim, a menos que eu esteja esquecendo algo, acho que é um princípio seguro. Pense um pouco em cada caso. Se você estiver trabalhando com uma conexão, por exemplo, não deseja fazê- Dispose()la prematuramente e precisará se reconectar alguns segundos depois, se a conexão existente for reutilizável. Da mesma forma, você não deseja desnecessariamente Dispose()imagens ou outras estruturas que possa acabar reconstruindo em um ou dois minutos.
svidgen
Compreendo. Mas, no caso específico de HttpClient e HttpClientHandler, sobre o qual esta pergunta se refere, eles estão mantendo um recurso aberto, como uma conexão HTTP? Se é isso que está acontecendo, talvez seja necessário repensar meu padrão de uso.
Fernando Correia
1
@DPeden Sua resposta não está em conflito com a minha. Observe, eu disse, você deve Dispose () de suas instâncias assim que estiver totalmente pronto e apto . Se você planeja usar a instância novamente, não está pronto .
Svidgen
9

Dispose () chama o código abaixo, que fecha as conexões abertas pela instância HttpClient. O código foi criado descompilando com dotPeek.

HttpClientHandler.cs - Dispose

ServicePointManager.CloseConnectionGroups(this.connectionGroupName);

Se você não chamar a disposição, o ServicePointManager.MaxServicePointIdleTime, executado por um timer, fechará as conexões http. O padrão é 100 segundos.

ServicePointManager.cs

internal static readonly TimerThread.Callback s_IdleServicePointTimeoutDelegate = new TimerThread.Callback(ServicePointManager.IdleServicePointTimeoutCallback);
private static volatile TimerThread.Queue s_ServicePointIdlingQueue = TimerThread.GetOrCreateQueue(100000);

private static void IdleServicePointTimeoutCallback(TimerThread.Timer timer, int timeNoticed, object context)
{
  ServicePoint servicePoint = (ServicePoint) context;
  if (Logging.On)
    Logging.PrintInfo(Logging.Web, SR.GetString("net_log_closed_idle", (object) "ServicePoint", (object) servicePoint.GetHashCode()));
  lock (ServicePointManager.s_ServicePointTable)
    ServicePointManager.s_ServicePointTable.Remove((object) servicePoint.LookupString);
  servicePoint.ReleaseAllConnectionGroups();
}

Se você não definiu o tempo ocioso como infinito, parece seguro não chamar o descarte e deixe o timer de conexão ociosa entrar e fechar as conexões para você, embora seja melhor chamar o descarte em uma declaração de uso se você sabe que terminou uma instância HttpClient e libera os recursos mais rapidamente.

Timothy Gonzalez
fonte
1
Você também pode ver o código no github. github.com/dotnet/corefx/blob/master/src/System.Net.Http/src/...
TamusJRoyce
8

Resposta curta: Não, a declaração da resposta atualmente aceita NÃO é precisa : "O consenso geral é que você não precisa (não deve) descartar o HttpClient".

Resposta longa : AMBAS as seguintes afirmações são verdadeiras e realizáveis ​​ao mesmo tempo:

  1. "O HttpClient deve ser instanciado uma vez e reutilizado ao longo da vida de um aplicativo", citado na documentação oficial .
  2. Um IDisposableobjeto deve / deve ser descartado.

E eles NÃO NECESSARIAMENTE CONFLITO entre si. É apenas uma questão de como você organiza seu código para reutilizar um HttpClientE ainda o descarta corretamente.

Uma resposta ainda mais citada da minha outra resposta :

Não é coincidência ver pessoas em algumas postagens do blog culpando como HttpClienta IDisposableinterface as faz tender a usar o using (var client = new HttpClient()) {...}padrão e, em seguida, levar a um problema esgotado de manipulador de soquete.

Eu acredito que isso se resume a uma concepção não dita (mis?): "Espera-se que um objeto IDisposable tenha vida curta" .

NO ENTANTO, embora certamente pareça algo de curta duração quando escrevemos código neste estilo:

using (var foo = new SomeDisposableObject())
{
    ...
}

a documentação oficial sobre IDisposable nunca menciona que os IDisposableobjetos precisam ter vida curta. Por definição, IDisposable é apenas um mecanismo que permite liberar recursos não gerenciados. Nada mais. Nesse sentido, espera-se que você ative o descarte, mas isso não exige que você faça isso de maneira breve.

Portanto, é seu trabalho escolher adequadamente quando acionar o descarte, com base nos requisitos do ciclo de vida do seu objeto real. Não há nada que o impeça de usar um IDisposable de uma maneira duradoura:

using System;
namespace HelloWorld
{
    class Hello
    {
        static void Main()
        {
            Console.WriteLine("Hello World!");

            using (var client = new HttpClient())
            {
                for (...) { ... }  // A really long loop

                // Or you may even somehow start a daemon here

            }

            // Keep the console window open in debug mode.
            Console.WriteLine("Press any key to exit.");
            Console.ReadKey();
        }
    }
}

Com esse novo entendimento, agora que revisitamos a postagem do blog , podemos observar claramente que a "correção" é inicializada HttpClientuma vez, mas nunca a elimina, é por isso que podemos ver em sua saída netstat que a conexão permanece no estado ESTABLISHED, o que significa que NÃO foi fechado corretamente. Se estivesse fechado, seu estado estaria em TIME_WAIT. Na prática, não é grande coisa vazar apenas uma conexão aberta após todo o programa terminar, e o pôster do blog ainda vê um ganho de desempenho após a correção; mas ainda assim, é conceitualmente incorreto culpar o IDisposable e optar por NÃO descartá-lo.

RayLuo
fonte
obrigado por esta explicação. Está claramente esclarecido um pouco sobre o consenso. Na sua opinião, quando você acha adequado ligar HttpClient.Dispose?
Jeson Martajaya 17/05/19
@JesonMartajaya, descarte-o quando seu aplicativo não precisar mais usar a instância httpClient. Você pode pensar que essa sugestão parece vaga, mas na verdade pode se alinhar perfeitamente com o ciclo de vida de sua HttpClient clientvariável, que é algo que você provavelmente já está fazendo de qualquer maneira. Você ainda pode usar using (...) {...}também. Por exemplo, veja a amostra Hello World na minha resposta.
RayLuo 19/05/19
7

Como parece que ninguém o mencionou aqui ainda, a nova melhor maneira de gerenciar o HttpClient e o HttpClientHandler no .Net Core 2.1 é usando o HttpClientFactory .

Ele resolve a maioria dos problemas e dicas mencionados de maneira limpa e fácil de usar. Do ótimo post de Steve Gordon :

Adicione os seguintes pacotes ao seu projeto .Net Core (2.1.1 ou posterior):

Microsoft.AspNetCore.All
Microsoft.Extensions.Http

Adicione isso ao Startup.cs:

services.AddHttpClient();

Injetar e usar:

[Route("api/[controller]")]
public class ValuesController : Controller
{
    private readonly IHttpClientFactory _httpClientFactory;

    public ValuesController(IHttpClientFactory httpClientFactory)
    {
        _httpClientFactory = httpClientFactory;
    }

    [HttpGet]
    public async Task<ActionResult> Get()
    {
        var client = _httpClientFactory.CreateClient();
        var result = await client.GetStringAsync("http://www.google.com");
        return Ok(result);
    }
}

Explore a série de postagens no blog de Steve para obter mais recursos.

pcdev
fonte
4

No meu caso, eu estava criando um HttpClient dentro de um método que realmente fez a chamada de serviço. Algo como:

public void DoServiceCall() {
  var client = new HttpClient();
  await client.PostAsync();
}

Em uma função de trabalhador do Azure, depois de chamar repetidamente esse método (sem descartar o HttpClient), acabaria por falhar com SocketException(falha na tentativa de conexão).

Tornei o HttpClient uma variável de instância (descartando-a no nível da classe) e o problema desapareceu. Então, eu diria que sim, descarte o HttpClient, assumindo que é seguro (você não tem chamadas assíncronas pendentes) para fazê-lo.

David Faivre
fonte
Obrigado pelo feedback. Esta é uma questão um pouco complexa. Eu recomendo a leitura dos artigos relacionados na resposta do DPeden. Em resumo, a instância HttpClient deve ser reutilizada durante todo o ciclo de vida do aplicativo. Se você criar novas instâncias repetidamente, pode ser necessário descartá-las.
Fernando Correia
6
"a instância HttpClient deve ser reutilizada durante todo o ciclo de vida do aplicativo", isso não é uma boa idéia para muitos aplicativos. Estou pensando em aplicativos da web que usam HttpClient. O HttpClient mantém o estado (por exemplo, os cabeçalhos de solicitação que ele usará); portanto, um encadeamento de solicitação da Web pode facilmente atropelar o que outro está fazendo. Em grandes aplicativos da web, também vi o HttpClient como o principal problema de conexão. Na dúvida, digo Dispose.
bytedev
@nashwan você não pode limpar os cabeçalhos e adicionar novos antes de cada solicitação?
precisa saber é o seguinte
A Microsoft também recomenda a reutilização de instâncias HttpClient - docs.microsoft.com/en-us/aspnet/web-api/overview/advanced/…
Mandeep Janjua
@MandeepJanjua esse exemplo parece ser um cliente como um aplicativo de console. Eu estava me referindo a um aplicativo da Web sendo o cliente.
bytedev
3

No uso típico (respostas <2GB), não é necessário Dispose the HttpResponseMessages.

Os tipos de retorno dos métodos HttpClient devem ser Dispostos se o Conteúdo do Fluxo não for totalmente lido. Caso contrário, não há como o CLR saber que esses fluxos podem ser fechados até serem coletados como lixo.

  • Se você estiver lendo os dados em um byte [] (por exemplo, GetByteArrayAsync) ou string, todos os dados serão lidos, portanto, não há necessidade de descarte.
  • As outras sobrecargas terão como padrão a leitura do fluxo de até 2 GB (HttpCompletionOption é ResponseContentRead, HttpClient.MaxResponseContentBufferSize o padrão é 2 GB)

Se você definir o HttpCompletionOption como ResponseHeadersRead ou a resposta for maior que 2 GB, você deverá limpar. Isso pode ser feito chamando Dispose no HttpResponseMessage ou chama Dispose / Close no Stream obtido a partir do conteúdo HttpResonseMessage ou lendo o conteúdo completamente.

O fato de você chamar Dispose no HttpClient depende se você deseja cancelar solicitações pendentes ou não.

Tom Deseyn
fonte
2

Se você deseja descartar o HttpClient, poderá configurá-lo como um pool de recursos. E no final do seu aplicativo, você descarta seu pool de recursos.

Código:

// Notice that IDisposable is not implemented here!
public interface HttpClientHandle
{
    HttpRequestHeaders DefaultRequestHeaders { get; }
    Uri BaseAddress { get; set; }
    // ...
    // All the other methods from peeking at HttpClient
}

public class HttpClientHander : HttpClient, HttpClientHandle, IDisposable
{
    public static ConditionalWeakTable<Uri, HttpClientHander> _httpClientsPool;
    public static HashSet<Uri> _uris;

    static HttpClientHander()
    {
        _httpClientsPool = new ConditionalWeakTable<Uri, HttpClientHander>();
        _uris = new HashSet<Uri>();
        SetupGlobalPoolFinalizer();
    }

    private DateTime _delayFinalization = DateTime.MinValue;
    private bool _isDisposed = false;

    public static HttpClientHandle GetHttpClientHandle(Uri baseUrl)
    {
        HttpClientHander httpClient = _httpClientsPool.GetOrCreateValue(baseUrl);
        _uris.Add(baseUrl);
        httpClient._delayFinalization = DateTime.MinValue;
        httpClient.BaseAddress = baseUrl;

        return httpClient;
    }

    void IDisposable.Dispose()
    {
        _isDisposed = true;
        GC.SuppressFinalize(this);

        base.Dispose();
    }

    ~HttpClientHander()
    {
        if (_delayFinalization == DateTime.MinValue)
            _delayFinalization = DateTime.UtcNow;
        if (DateTime.UtcNow.Subtract(_delayFinalization) < base.Timeout)
            GC.ReRegisterForFinalize(this);
    }

    private static void SetupGlobalPoolFinalizer()
    {
        AppDomain.CurrentDomain.ProcessExit +=
            (sender, eventArgs) => { FinalizeGlobalPool(); };
    }

    private static void FinalizeGlobalPool()
    {
        foreach (var key in _uris)
        {
            HttpClientHander value = null;
            if (_httpClientsPool.TryGetValue(key, out value))
                try { value.Dispose(); } catch { }
        }

        _uris.Clear();
        _httpClientsPool = null;
    }
}

manipulador var = HttpClientHander.GetHttpClientHandle (new Uri ("URL base")).

  • HttpClient, como uma interface, não pode chamar Dispose ().
  • Dispose () será chamado de forma atrasada pelo Garbage Collector. Ou quando o programa limpa o objeto através de seu destruidor.
  • Usa referências fracas + lógica de limpeza atrasada, para que permaneça em uso enquanto for reutilizada com freqüência.
  • Ele aloca apenas um novo HttpClient para cada URL base passado para ele. Os motivos explicados por Ohad Schneider respondem abaixo. Mau comportamento ao alterar o URL base.
  • HttpClientHandle permite zombar nos testes
TamusJRoyce
fonte
Perfeito. Vejo que você chama o Disposemétodo que se registra no GC. Isso deve ser classificado mais alto na parte superior.
Jeson Martajaya 17/05/19
Observe que o HttpClient faz o pool de recursos por URL base. Portanto, se você estiver acessando milhares de sites diferentes em uma lista, seu desempenho será prejudicado sem limpar esses sites individuais. Isso expõe a capacidade de descartar cada URL base. No entanto, se você estiver usando apenas um site, pode ser apenas por razões acadêmicas para chamar de descarte.
TamusJRoyce 18/05/19
1

O uso da injeção de dependência em seu construtor facilita o gerenciamento do tempo de vida do seu HttpClient- tirando o gerenciamento do tempo de vida fora do código necessário e tornando-o facilmente alterável posteriormente.

Minha preferência atual é criar uma classe de cliente http separada que herda HttpClientuma vez por domínio de terminal de destino e, em seguida, torná-lo um singleton usando injeção de dependência.public class ExampleHttpClient : HttpClient { ... }

Em seguida, tomo uma dependência de construtor no cliente http personalizado nas classes de serviço em que preciso acessar essa API. Isso resolve o problema da vida útil e tem vantagens quando se trata de pool de conexões.

Você pode ver um exemplo resolvido na resposta relacionada em https://stackoverflow.com/a/50238944/3140853

alastairtree
fonte
-2

Eu acho que se deve usar o padrão singleton para evitar ter que criar instâncias do HttpClient e fechá-lo o tempo todo. Se você estiver usando o .Net 4.0, poderá usar um código de exemplo como abaixo. para obter mais informações sobre o padrão singleton, clique aqui .

class HttpClientSingletonWrapper : HttpClient
{
    private static readonly Lazy<HttpClientSingletonWrapper> Lazy= new Lazy<HttpClientSingletonWrapper>(()=>new HttpClientSingletonWrapper()); 

    public static HttpClientSingletonWrapper Instance {get { return Lazy.Value; }}

    private HttpClientSingletonWrapper()
    {
    }
}

Use o código como abaixo.

var client = HttpClientSingletonWrapper.Instance;
yayadavid
fonte
3
Algo que atente para quando está fazendo isso (e outros regimes semelhantes): " Os membros de instância não são garantidos para ser thread-safe. "
tne
2
Se esta resposta está correta ou não, deve ser totalmente dependente do aplicativo que você deseja usar o HttpClient. Se você tiver um aplicativo da Web e criar um HttpClient singleton que todas as solicitações da Web compartilhariam, você poderá receber muitas exceções de conexão (dependendo da popularidade do seu site! :-)). (Veja a resposta de David Faivre)
bytedev