¿HttpClient y HttpClientHandler deben eliminarse entre solicitudes?

334

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 usingdocumentació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:

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:

  1. ¿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.

  2. Si no es necesario, ¿sería una "buena práctica" de todos modos, ya que implementan IDisposable?

  3. Si es necesario (o recomendado), ¿ este código mencionado anteriormente lo implementa de manera segura (para .NET Framework 4.5)?

  4. Si estas clases no requieren llamar a Dispose (), ¿por qué se implementaron como IDisposable?

  5. Si lo requieren, o si es una práctica recomendada, ¿son los ejemplos de Microsoft engañosos o inseguros?

Fernando Correia
fuente
2
@Damien_The_Unbeliever, gracias por tus comentarios. ¿Tiene alguna sugerencia sobre cómo podría aclarar la pregunta? Quiero saber si puede conducir a los problemas generalmente asociados con la no disposición de recursos, como la fuga de recursos y la corrupción de datos.
Fernando Correia
99
@Damien_The_Unbeliever: No es cierto. En particular, los escritores de secuencias deben estar dispuestos a tener un comportamiento correcto.
Stephen Cleary
1
@StephenCleary: ¿en qué aspectos estás pensando? Ciertamente, puede recurrir Flusha 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"?
Damien_The_Unbeliever
1
Esto es completamente incorrecto: "Como regla general, cuando usa un objeto IDisposable, debe declararlo e instanciarlo en una declaración de uso". Leería la documentación sobre la clase que implementa IDisposable siempre antes de decidir si debo usar un uso para ello. Como el autor de las bibliotecas donde implemento IDisposable necesita liberar recursos no administrados, me horrorizaría si los consumidores crearan una instancia dispuesta cada vez en lugar de reutilizar una instancia existente. Esto no quiere decir No se deshaga de las instancias, ..
markmnl
1
He enviado un RP a microsoft para actualizar sus documentos: github.com/dotnet/docs/pull/2470
markmnl

Respuestas:

259

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í:

Aunque HttpClient implementa indirectamente la interfaz IDisposable, el uso estándar de HttpClient no es deshacerse de ella después de cada solicitud. El objeto HttpClient está destinado a vivir mientras su aplicación necesite realizar solicitudes HTTP. Tener un objeto en varias solicitudes habilita un lugar para configurar DefaultRequestHeaders y evita que tenga que volver a especificar cosas como CredentialCache y CookieContainer en cada solicitud, como era necesario con HttpWebRequest.

O incluso abrir DotPeek.

David Peden
fuente
64
Para aclarar su respuesta, ¿sería correcto decir que "no necesita deshacerse de HttpClient SI ESPERA LA INSTANCIA PARA REUTILIZARLO MÁS TARDE"? Por ejemplo, si se llama a un método repetidamente y crea una nueva instancia de HttpClient (aunque no es el patrón recomendado en la mayoría de los casos), ¿sería correcto decir que este método no debería eliminar la instancia (que no se reutilizará)? Podría conducir a miles de instancias no expuestas. En otras palabras, ¿debería intentar reutilizar las instancias, pero si no las reutiliza, será mejor que las elimine (para liberar las conexiones)?
Fernando Correia
8
Creo que la respuesta comprensiblemente frustrante pero correcta es que depende. Si tuviera que fijarme para dar consejos generales que funcionaron en la mayoría de los casos (nunca digo todos), sugeriría que use un contenedor de IoC y registre una instancia de HttpClient como singleton. La vida útil de la instancia se limitaría a la vida útil del contenedor. Esto podría tener un alcance a nivel de aplicación o tal vez por solicitud en una aplicación web.
David Peden
25
@FernandoCorreia Sí. Si por alguna razón crea y destruye repetidamente instancias HttpClient, entonces sí, debe deshacerse de él. No sugiero ignorar la interfaz IDisposable, solo trato de alentar a las personas a reutilizar las instancias.
Darrel Miller
20
Solo para agregar más credibilidad a esta respuesta, hoy hablé con el equipo de HttpClient y confirmaron que HttpClient no fue diseñado para usarse por solicitud. Una instancia de HttpClient debe mantenerse viva mientras una aplicación cliente continúa interactuando con un host en particular.
Darrel Miller
19
@DavidPeden Registrar HttpClient como singleton me parece peligroso porque es mutable. Por ejemplo, ¿no se Timeoutestarían pisoteando todos los que se asignan a la propiedad?
Jon-Eric
47

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.

  1. En términos generales, la mayoría de los IDisposableobjetos deberían desecharse idealmente cuando haya terminado con ellos , especialmente aquellos que poseen recursos de SO nombrados / compartidos . HttpClientno 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.
  2. Sin embargo, la mejor práctica para HttpClient dice que debe crear una instancia y reutilizarla tanto como sea posible (utilizando sus miembros seguros para subprocesos en escenarios de subprocesos múltiples). Por lo tanto, en la mayoría de los escenarios , nunca lo eliminará simplemente porque lo necesitará todo el tiempo .
  3. El problema con la reutilización del mismo HttpClient "para siempre" es que la conexión HTTP subyacente puede permanecer abierta contra la IP resuelta originalmente por DNS, independientemente de los cambios de DNS . Esto puede ser un problema en escenarios como la implementación azul / verde y la conmutación por error basada en DNS . Existen varios enfoques para tratar este problema, el más confiable es que el servidor envíe un Connection:closeencabezado después de que se realicen los cambios de DNS. Otra posibilidad consiste en reciclar el HttpClientlado 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).
Ohad Schneider
fuente
Lo dispongo todo el tiempo ya que no puedo cambiar el proxy en una instancia;)
ed22
Si necesita deshacerse del HttpClient por cualquier razón, debe mantener una instancia estática del HttpMessageHandler, ya que deshacerse de él es la causa de los problemas atribuidos a la eliminación del HttpClient. HttpClient tiene una sobrecarga del constructor que le permite especificar que el controlador suministrado no debe desecharse, en cuyo caso puede reutilizar el HttpMessageHandler con otras instancias de HttpClient.
Tom Lint el
Debe conservar su HttpClient, pero puede usar algo como System.Net.ServicePointManager.DnsRefreshTimeout = 3000; Esto es útil, por ejemplo, si está en un dispositivo móvil que en cualquier momento puede cambiar entre wifi y 4G.
Johan Franzén
18

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 HttpClientse utiliza. En casos similares, llamar explícitamente Dispose()es algo superfluo.

Pero, en general, cuando una clase se implementa IDisposable, el entendimiento es que debe conocer Dispose()sus instancias tan pronto como esté completamente listo y capaz. Creo que esto es particularmente cierto en casos HttpClienten 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á renunciar Dipose()a ella; en ese caso, no está "completamente listo".

Ver también: IDisposable.Dispose Method y cuándo llamar Dispose

svidgen
fuente
77
Es como si alguien trae un plátano a su casa, se lo come y está de pie con la cáscara. ¿Qué deberían hacer con la cáscara? ... Si están saliendo por la puerta con él, déjalos ir. Si se quedan, haz que la tiren a la basura para que no apesta el lugar.
svidgen
solo para aclarar esta respuesta, ¿estás diciendo, "no es necesario deshacerse si el programa va a terminar justo después de usarlo"? ¿Y que debería deshacerse si se espera que el programa continúe durante algún tiempo haciendo otras cosas?
Fernando Correia
@FernandoCorreia Sí, a menos que me olvide de algo, creo que es un principio seguro. Sin embargo, piense en cada caso. Si está trabajando con una conexión, por ejemplo, no desea 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 innecesariamente Dispose()imágenes u otras estructuras que podría tener que reconstruir en un minuto o dos.
svidgen
Entiendo. Pero en el caso particular de HttpClient y HttpClientHandler sobre el que trata esta pregunta, ¿mantienen abierto un recurso como una conexión HTTP? Si eso es lo que está sucediendo, podría tener que repensar mi patrón de uso.
Fernando Correia
1
@DPeden Tu respuesta no está en conflicto con la mía. Tenga en cuenta que le dije que debería deshacerse () de sus instancias tan pronto como esté completamente listo y en condiciones . Si planea usar la instancia nuevamente, no está listo .
svidgen
9

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

ServicePointManager.CloseConnectionGroups(this.connectionGroupName);

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

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();
}

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.

Timothy Gonzalez
fuente
1
También puedes ver el código en github. github.com/dotnet/corefx/blob/master/src/System.Net.Http/src/…
TamusJRoyce
8

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:

  1. "HttpClient está destinado a ser instanciado una vez y reutilizado a lo largo de la vida de una aplicación", citado de la documentación oficial .
  2. Se IDisposablesupone / 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 HttpClientAND 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 HttpClientla IDisposableinterfaz hace que usen el using (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:

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

La documentación oficial sobre IDisposable nunca menciona que los IDisposableobjetos 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:

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();
        }
    }
}

Con esta nueva comprensión, ahora que volvemos a visitar esa publicación de blog , podemos notar claramente que la "corrección" se inicializa HttpClientuna 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.

RayLuo
fuente
gracias por esta explicacion. Claramente arroja algo de luz hacia el consenso. Desde tu opinión, ¿cuándo crees que es apropiado llamar HttpClient.Dispose?
Jeson Martajaya
@JesonMartajaya, deséchelo cuando su aplicación ya no necesite usar la instancia httpClient. Puede pensar que tal sugerencia suena vaga, pero de hecho puede alinearse perfectamente con el ciclo de vida de su HttpClient clientvariable, que es una cosa de Programación-101 que presumiblemente ya está haciendo de todos modos. Incluso podría ser capaz de usar using (...) {...}también. Por ejemplo, vea la muestra Hello World dentro de mi respuesta.
RayLuo
7

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):

Microsoft.AspNetCore.All
Microsoft.Extensions.Http

Agregue esto a Startup.cs:

services.AddHttpClient();

Inyectar y 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 la serie de publicaciones en el blog de Steve para obtener muchas más funciones.

pcdev
fuente
4

En mi caso, estaba creando un HttpClient dentro de un método que realmente hizo la llamada de servicio. Algo como:

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

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.

David Faivre
fuente
Gracias por la respuesta. Este es un tema algo complejo. Recomiendo leer los artículos vinculados en la respuesta de DPeden. En resumen, la instancia de HttpClient debe reutilizarse durante todo el ciclo de vida de la aplicación. Si crea nuevas instancias repetidamente, es posible que deba deshacerse de ellas.
Fernando Correia
66
"la instancia de HttpClient debe reutilizarse a lo largo del ciclo de vida de la aplicación", esta no es una buena idea con muchas aplicaciones. Estoy pensando en aplicaciones web que usan HttpClient. HttpClient mantiene el estado (por ejemplo, los encabezados de solicitud que usará), por lo que un hilo de solicitud web podría pisotear fácilmente lo que está haciendo otro. En aplicaciones web grandes también he visto a HttpClient como el problema de los principales problemas de conexión. En caso de duda, digo Eliminar.
bytedev
@nashwan, ¿no puedes borrar los encabezados y agregar nuevos antes de cada solicitud?
Mandeep Janjua
Microsoft también recomienda reutilizar instancias HttpClient - docs.microsoft.com/en-us/aspnet/web-api/overview/advanced/…
Mandeep Janjua
@MandeepJanjua ese ejemplo parece ser un cliente como una aplicación de consola. Me refería a una aplicación web que era el cliente.
bytedev
3

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 está leyendo los datos en un byte [] (por ejemplo, GetByteArrayAsync) o cadena, todos los datos se leen, por lo que no es necesario deshacerse de ellos.
  • Las otras sobrecargas tendrán un valor predeterminado de lectura de Stream de hasta 2 GB (HttpCompletionOption es ResponseContentRead, HttpClient.MaxResponseContentBufferSize predeterminado es 2 GB)

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.

Tom Deseyn
fuente
2

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:

// 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;
    }
}

controlador de var = HttpClientHander.GetHttpClientHandle (nuevo Uri ("url base")).

  • HttpClient, como interfaz, no puede llamar a Dispose ().
  • Dispose () será llamado de manera retrasada por el recolector de basura. O cuando el programa limpia el objeto a través de su destructor.
  • Utiliza referencias débiles + lógica de limpieza retrasada para que permanezca en uso siempre que se reutilice con frecuencia.
  • Solo asigna un nuevo HttpClient para cada URL base que se le pasa. Las razones explicadas por Ohad Schneider responden a continuación. Mal comportamiento al cambiar la URL base.
  • HttpClientHandle permite burlarse en las pruebas
TamusJRoyce
fuente
Perfecto. Veo que recurres Disposeal método que registras en GC. Esto debería ser calificado más alto en la parte superior.
Jeson Martajaya
Tenga en cuenta que HttpClient agrupa los recursos por URL base. Entonces, si está llegando a miles de sitios web diferentes en una lista, su rendimiento se degradará sin limpiar esos sitios individuales. Esto expone la capacidad de disponer de cada base-url. Sin embargo, si solo usa un sitio web, puede ser solo por razones académicas para llamar a disposed.
TamusJRoyce
1

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 HttpClientuna 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

alastairtree
fuente
-2

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í .

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 el código de la siguiente manera.

var client = HttpClientSingletonWrapper.Instance;
yayadavid
fuente
3
Algo a tener en cuenta cuando se hace esto (y otros esquemas similares): " los miembros de instancias no están garantizados para estar seguro de rosca. "
TNE
2
Si esta respuesta es correcta o no, debería depender totalmente de la aplicación desde la que desea utilizar HttpClient. Si tiene una aplicación web y crea un HttpClient único que todas las solicitudes web compartirían, posiblemente obtendrá muchas excepciones de conexión (¡dependiendo de cuán popular sea su sitio web! :-)). (Ver la respuesta de David Faivre)
bytedev