System.Net.Http.HttpClient e System.Net.Http.HttpClientHandler no .NET Framework 4.5 implementam IDisposable (via System.Net.Http.HttpMessageInvoker ).
A using
documentaçã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:
- O artigo original do blog anunciando a relase do HttpClient.
- A documentação real do MSDN para HttpClient.
- BingTranslateSample
- GoogleMapsSample
- WorldBankSample
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:
É 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.
Se não for necessário, seria uma "boa prática", já que eles implementam IDisposable?
Se for necessário (ou recomendado), esse código mencionado acima está implementando-o com segurança (no .NET Framework 4.5)?
Se essas classes não exigem a chamada Dispose (), por que elas foram implementadas como IDisposable?
Se eles exigirem ou se for uma prática recomendada, os exemplos da Microsoft são enganosos ou inseguros?
fonte
Flush
um 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"?Respostas:
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:
Ou até mesmo abra o DotPeek.
fonte
Timeout
propriedade não deveriam pisar um no outro?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.
IDisposable
objetos deve ser descartada idealmente quando você terminar com eles , especialmente aqueles que possuem recursos de SO nomeado / compartilhado .HttpClient
nã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.Connection:close
cabeçalho após a alteração do DNS. Outra possibilidade envolve reciclarHttpClient
no 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).fonte
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
HttpClient
uso. Em casos semelhantes, chamar explicitamenteDispose()
é um tanto supérfluo.Mas, em geral, quando uma classe é implementada
IDisposable
, o entendimento é que você deve terDispose()
suas instâncias assim que estiver totalmente pronto e apto. Eu diria que isso é particularmente verdadeiro em casos como osHttpClient
em 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 renunciarDipose()
a ela - você não está "totalmente pronto" nesse caso.Consulte também: Método IDisposable.Dispose e Quando chamar Dispose
fonte
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 desnecessariamenteDispose()
imagens ou outras estruturas que possa acabar reconstruindo em um ou dois minutos.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
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
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.
fonte
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:
IDisposable
objeto 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
HttpClient
E 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
HttpClient
aIDisposable
interface as faz tender a usar ousing (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:
a documentação oficial sobre IDisposable nunca menciona que os
IDisposable
objetos 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:
Com esse novo entendimento, agora que revisitamos a postagem do blog , podemos observar claramente que a "correção" é inicializada
HttpClient
uma 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.fonte
HttpClient.Dispose
?HttpClient client
variável, que é algo que você provavelmente já está fazendo de qualquer maneira. Você ainda pode usarusing (...) {...}
também. Por exemplo, veja a amostra Hello World na minha resposta.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):
Adicione isso ao Startup.cs:
Injetar e usar:
Explore a série de postagens no blog de Steve para obter mais recursos.
fonte
No meu caso, eu estava criando um HttpClient dentro de um método que realmente fez a chamada de serviço. Algo como:
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.
fonte
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ê 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.
fonte
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:
manipulador var = HttpClientHander.GetHttpClientHandle (new Uri ("URL base")).
fonte
Dispose
método que se registra no GC. Isso deve ser classificado mais alto na parte superior.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
HttpClient
uma 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
fonte
Leia a minha resposta a uma pergunta muito semelhante postada abaixo. Deve ficar claro que você deve tratar as
HttpClient
instâncias como singletons e reutilizar as solicitações.Qual é a sobrecarga de criar um novo HttpClient por chamada em um cliente WebAPI?
fonte
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 .
Use o código como abaixo.
fonte