System.Net.Http.HttpClient y System.Net.Http.HttpClientHandler en .NET Framework 4.5 implementan IDisposable (a través de System.Net.Http.HttpMessageInvoker ).
La using
documentación de la declaración dice:
Como regla general, cuando usa un objeto IDisposable, debe declararlo e instanciarlo en una declaración de uso.
Esta respuesta usa este patrón:
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();
}
Pero los ejemplos más visibles de Microsoft no llaman Dispose()
explícita o implícitamente. Por ejemplo:
- El artículo original del blog que anuncia la transmisión de HttpClient.
- La documentación real de MSDN para HttpClient.
- BingTranslateSample
- GoogleMapsSample
- WorldBankSample
En los comentarios del anuncio , alguien le preguntó al empleado de Microsoft:
Después de verificar sus muestras, vi que no realizó la acción de eliminación en la instancia de HttpClient. He usado todas las instancias de HttpClient con el uso de la declaración en mi aplicación y pensé que es la forma correcta ya que HttpClient implementa la interfaz IDisposable. ¿Estoy en el camino correcto?
Su respuesta fue:
En general, eso es correcto, aunque debe tener cuidado con "usar" y asíncrono ya que realmente no se mezclan en .Net 4, en .Net 4.5 puede usar "esperar" dentro de una declaración "usar".
Por cierto, puede reutilizar el mismo HttpClient tantas veces como desee, por lo que normalmente no los creará / eliminará todo el tiempo.
El segundo párrafo es superfluo para esta pregunta, que no le preocupa cuántas veces puede usar una instancia de HttpClient, sino si es necesario deshacerse de ella después de que ya no la necesite.
(Actualización: de hecho, el segundo párrafo es la clave de la respuesta, como se proporciona a continuación por @DPeden).
Entonces mis preguntas son:
¿Es necesario, dada la implementación actual (.NET Framework 4.5), llamar a Dispose () en instancias HttpClient y HttpClientHandler? Aclaración: por "necesario" me refiero a si hay consecuencias negativas por no deshacerse, como la fuga de recursos o los riesgos de corrupción de datos.
Si no es necesario, ¿sería una "buena práctica" de todos modos, ya que implementan IDisposable?
Si es necesario (o recomendado), ¿ este código mencionado anteriormente lo implementa de manera segura (para .NET Framework 4.5)?
Si estas clases no requieren llamar a Dispose (), ¿por qué se implementaron como IDisposable?
Si lo requieren, o si es una práctica recomendada, ¿son los ejemplos de Microsoft engañosos o inseguros?
fuente
Flush
a uno después de cada escritura, y aparte del inconveniente de que continúe reteniendo los recursos subyacentes durante más tiempo del necesario, ¿qué no ocurrirá que sea necesario para un "comportamiento correcto"?Respuestas:
El consenso general es que no necesita (no debería) deshacerse de HttpClient.
Muchas personas que están íntimamente involucradas en la forma en que funciona lo han dicho.
Consulte la publicación de blog de Darrel Miller y una publicación SO relacionada: el rastreo de HttpClient da como resultado una pérdida de memoria como referencia.
También le sugiero encarecidamente que lea el capítulo HttpClient de Diseño de API web evolucionables con ASP.NET para ver el contexto de lo que sucede debajo del capó, en particular la sección "Ciclo de vida" citada aquí:
O incluso abrir DotPeek.
fuente
Timeout
estarían pisoteando todos los que se asignan a la propiedad?Las respuestas actuales son un poco confusas y engañosas, y les faltan algunas implicaciones importantes de DNS. Trataré de resumir dónde están las cosas claramente.
IDisposable
objetos deberían desecharse idealmente cuando haya terminado con ellos , especialmente aquellos que poseen recursos de SO nombrados / compartidos .HttpClient
no es una excepción, ya que, como señala Darrel Miller , asigna tokens de cancelación y los cuerpos de solicitud / respuesta pueden ser flujos no administrados.Connection:close
encabezado después de que se realicen los cambios de DNS. Otra posibilidad consiste en reciclar elHttpClient
lado del cliente, ya sea periódicamente o mediante algún mecanismo que aprenda sobre el cambio de DNS. Consulte https://github.com/dotnet/corefx/issues/11224 para obtener más información (sugiero leerlo detenidamente antes de usar a ciegas el código sugerido en la publicación del blog vinculada).fuente
Según tengo entendido, la llamada
Dispose()
es necesaria solo cuando está bloqueando los recursos que necesita más adelante (como una conexión particular). Siempre se recomienda liberar recursos que ya no está utilizando, incluso si no los necesita de nuevo, simplemente porque generalmente no debería estar reteniendo recursos que no está utilizando (juego de palabras).El ejemplo de Microsoft no es incorrecto, necesariamente. Todos los recursos utilizados se liberarán cuando la aplicación salga. Y en el caso de ese ejemplo, eso sucede casi inmediatamente después de que
HttpClient
se utiliza. En casos similares, llamar explícitamenteDispose()
es algo superfluo.Pero, en general, cuando una clase se implementa
IDisposable
, el entendimiento es que debe conocerDispose()
sus instancias tan pronto como esté completamente listo y capaz. Creo que esto es particularmente cierto en casosHttpClient
en los que no está documentado explícitamente si los recursos o las conexiones se mantienen / abren. En el caso en que la conexión se reutilizará nuevamente [pronto], querrá renunciarDipose()
a ella; en ese caso, no está "completamente listo".Ver también: IDisposable.Dispose Method y cuándo llamar Dispose
fuente
Dispose()
hacerlo prematuramente y tiene que volver a conectarse unos segundos más tarde si la conexión existente es reutilizable. Del mismo modo, no desea innecesariamenteDispose()
imágenes u otras estructuras que podría tener que reconstruir en un minuto o dos.Dispose () llama al código siguiente, que cierra las conexiones abiertas por la instancia HttpClient. El código fue creado descompilando con dotPeek.
HttpClientHandler.cs - Eliminar
Si no llama a dispose, ServicePointManager.MaxServicePointIdleTime, que se ejecuta mediante un temporizador, cerrará las conexiones http. El valor predeterminado es de 100 segundos.
ServicePointManager.cs
Si no ha establecido el tiempo de inactividad en infinito, entonces parece seguro no llamar a deshacerse y dejar que el temporizador de conexión inactiva se active y cierre las conexiones por usted, aunque sería mejor que llame a deshacerse en una declaración de uso si sabes que has terminado con una instancia de HttpClient y liberas los recursos más rápido.
fuente
Respuesta corta: No, la declaración en la respuesta actualmente aceptada NO es precisa : "El consenso general es que no es necesario (no debería) deshacerse de HttpClient".
Respuesta larga : AMBAS de las siguientes afirmaciones son verdaderas y alcanzables al mismo tiempo:
IDisposable
supone / se recomienda eliminar un objeto.Y NO NECESARIO CONFLICTAN entre sí. Es solo una cuestión de cómo organizar su código para reutilizar un
HttpClient
AND y aún disponerlo adecuadamente.Una respuesta aún más larga citada de mi otra respuesta :
No es una coincidencia ver a personas en algunas publicaciones de blog culpando de cómo
HttpClient
laIDisposable
interfaz hace que usen elusing (var client = new HttpClient()) {...}
patrón y luego lleven a un problema agotado del controlador de socket.Creo que eso se reduce a una concepción tácita (¿equivocada?): "Se espera que un objeto IDisposable sea de corta duración" .
SIN EMBARGO, aunque ciertamente parece algo de corta duración cuando escribimos código con este estilo:
La documentación oficial sobre IDisposable nunca menciona que los
IDisposable
objetos tienen que ser de corta duración. Por definición, IDisposable es simplemente un mecanismo para permitirle liberar recursos no administrados. Nada mas. En ese sentido, se ESPERA que eventualmente active la eliminación, pero no requiere que lo haga de manera efímera.Por lo tanto, es su trabajo elegir adecuadamente cuándo activar la eliminación, basándose en los requisitos del ciclo de vida de su objeto real. No hay nada que le impida usar un ID desechable de una manera duradera:
Con esta nueva comprensión, ahora que volvemos a visitar esa publicación de blog , podemos notar claramente que la "corrección" se inicializa
HttpClient
una vez pero nunca la elimina, es por eso que podemos ver en su salida de netstat que, la conexión permanece en estado ESTABLECIDO, lo que significa que tiene NO se ha cerrado correctamente. Si estuviera cerrado, su estado estaría en TIME_WAIT en su lugar. En la práctica, no es un gran problema perder solo una conexión abierta después de que termine todo el programa, y el póster del blog aún ve una ganancia de rendimiento después de la solución; pero aún así, es conceptualmente incorrecto culpar a IDisposable y elegir NO desecharlo.fuente
HttpClient.Dispose
?HttpClient client
variable, que es una cosa de Programación-101 que presumiblemente ya está haciendo de todos modos. Incluso podría ser capaz de usarusing (...) {...}
también. Por ejemplo, vea la muestra Hello World dentro de mi respuesta.Como no parece que nadie lo haya mencionado aquí todavía, la nueva mejor manera de administrar HttpClient y HttpClientHandler en .Net Core 2.1 es usar HttpClientFactory .
Resuelve la mayoría de los problemas y problemas mencionados anteriormente de una manera limpia y fácil de usar. De la gran publicación de blog de Steve Gordon :
Agregue los siguientes paquetes a su proyecto .Net Core (2.1.1 o posterior):
Agregue esto a Startup.cs:
Inyectar y usar:
Explore la serie de publicaciones en el blog de Steve para obtener muchas más funciones.
fuente
En mi caso, estaba creando un HttpClient dentro de un método que realmente hizo la llamada de servicio. Algo como:
En un rol de trabajador de Azure, después de llamar repetidamente a este método (sin eliminar el HttpClient), eventualmente fallará con
SocketException
(intento de conexión fallido)Hice el HttpClient una variable de instancia (eliminándolo a nivel de clase) y el problema desapareció. Entonces, diría que sí, deseche el HttpClient, suponiendo que sea seguro (no tiene llamadas asíncronas pendientes) para hacerlo.
fuente
En el uso típico (respuestas <2GB) no es necesario desechar los mensajes HttpResponseMessages.
Los tipos de retorno de los métodos HttpClient deben eliminarse si su contenido continuo no se lee completamente. De lo contrario, no hay forma de que el CLR sepa que esos flujos pueden cerrarse hasta que se recolecte basura.
Si configura HttpCompletionOption en ResponseHeadersRead o la respuesta es mayor que 2 GB, debe realizar la limpieza. Esto se puede hacer llamando a Dispose en el HttpResponseMessage o llamando a Dispose / Close en la secuencia obtenida del contenido de HttpResonseMessage o leyendo el contenido por completo.
Si llama a Dispose en el HttpClient depende de si desea cancelar las solicitudes pendientes o no.
fuente
Si desea deshacerse de HttpClient, puede hacerlo si lo configura como un grupo de recursos. Y al final de su aplicación, dispone de su grupo de recursos.
Código:
controlador de var = HttpClientHander.GetHttpClientHandle (nuevo Uri ("url base")).
fuente
Dispose
al método que registras en GC. Esto debería ser calificado más alto en la parte superior.El uso de la inyección de dependencias en su constructor facilita la administración de la vida útil de su empresa
HttpClient
: elimina la administración de la vida útil fuera del código que lo necesita y lo hace fácilmente modificable en una fecha posterior.Mi preferencia actual es crear una clase de cliente http separada que herede de
HttpClient
una vez por dominio de punto final de destino y luego convertirla en un singleton mediante inyección de dependencia.public class ExampleHttpClient : HttpClient { ... }
Luego tomo una dependencia del constructor en el cliente http personalizado en las clases de servicio donde necesito acceso a esa API. Esto resuelve el problema de por vida y tiene ventajas cuando se trata de la agrupación de conexiones.
Puede ver un ejemplo trabajado en la respuesta relacionada en https://stackoverflow.com/a/50238944/3140853
fuente
Lea mi respuesta a una pregunta muy similar publicada a continuación. Debe quedar claro que debe tratar las
HttpClient
instancias como singletons y reutilizarlas en las solicitudes.¿Cuál es la sobrecarga de crear un nuevo HttpClient por llamada en un cliente WebAPI?
fuente
Creo que uno debería usar el patrón singleton para evitar tener que crear instancias del HttpClient y cerrarlo todo el tiempo. Si está utilizando .Net 4.0, podría usar un código de muestra como se muestra a continuación. Para obtener más información sobre el patrón singleton, consulte aquí .
Use el código de la siguiente manera.
fuente