¿Cuál debería ser la HttpClientvida útil de un cliente WebAPI? 
 ¿Es mejor tener una instancia de HttpClientpara múltiples llamadas?
¿Cuál es la sobrecarga de crear y eliminar una HttpClientsolicitud por solicitud, como en el ejemplo a continuación (tomado de http://www.asp.net/web-api/overview/web-api-clients/calling-a-web-api-from- a-net-client ):
using (var client = new HttpClient())
{
    client.BaseAddress = new Uri("http://localhost:9000/");
    client.DefaultRequestHeaders.Accept.Clear();
    client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
    // New code:
    HttpResponseMessage response = await client.GetAsync("api/products/1");
    if (response.IsSuccessStatusCode)
    {
        Product product = await response.Content.ReadAsAsync<Product>();
        Console.WriteLine("{0}\t${1}\t{2}", product.Name, product.Price, product.Category);
    }
}
                    
                        c#
                                asp.net
                                web-services
                                asp.net-web-api
                                dotnet-httpclient
                                
                    
                    
                        Bruno Pessanha
fuente
                
                fuente

StopwatchSin embargo, no estoy seguro, podría usar la clase para compararla. Mi estimación sería que tiene más sentido tener una solaHttpClient, suponiendo que todas esas instancias se usen en el mismo contexto.Respuestas:
HttpClientha sido diseñado para ser reutilizado para múltiples llamadas . Incluso a través de múltiples hilos. ElHttpClientHandlertiene credenciales y las galletas que están destinados a ser reutilizada a través de las llamadas. Tener una nuevaHttpClientinstancia requiere volver a configurar todo eso. Además, laDefaultRequestHeaderspropiedad contiene propiedades destinadas a múltiples llamadas. Tener que restablecer esos valores en cada solicitud derrota el punto.Otro beneficio importante de
HttpClientes la capacidad de agregarHttpMessageHandlersa la tubería de solicitud / respuesta para aplicar preocupaciones transversales. Estos podrían ser para el registro, la auditoría, la limitación, el manejo de redireccionamiento, el manejo fuera de línea, la captura de métricas. Todo tipo de cosas diferentes. Si se crea un nuevo HttpClient en cada solicitud, entonces todos estos controladores de mensajes deben configurarse en cada solicitud y de alguna manera también se debe proporcionar cualquier estado de nivel de aplicación que se comparta entre las solicitudes de estos controladores.Cuanto más utilice las funciones
HttpClient, más verá que reutilizar una instancia existente tiene sentido.Sin embargo, el mayor problema, en mi opinión, es que cuando
HttpClientse elimina una clase, se eliminaHttpClientHandler, lo que luego cierra por la fuerza laTCP/IPconexión en el conjunto de conexiones que administraServicePointManager. Esto significa que cada solicitud con una nuevaHttpClientrequiere restablecer una nuevaTCP/IPconexión.Según mis pruebas, usando HTTP simple en una LAN, el impacto en el rendimiento es bastante insignificante. Sospecho que esto se debe a que hay un keepalive TCP subyacente que mantiene la conexión abierta incluso cuando
HttpClientHandlerintenta cerrarla.En las solicitudes que pasan por Internet, he visto una historia diferente. He visto un impacto de rendimiento del 40% debido a que tengo que volver a abrir la solicitud cada vez.
Sospecho que el golpe en una
HTTPSconexión sería aún peor.Mi consejo es mantener una instancia de HttpClient durante toda la vida útil de su aplicación para cada API distinta a la que se conecte.
fuente
which then forcibly closes the TCP/IP connection in the pool of connections that is managed by ServicePointManager¿Qué tan seguro está sobre esta declaración? Eso es difícil de creer.HttpClientme parece una unidad de trabajo que se supone que se instancia a menudo.Si desea que su aplicación se amplíe, ¡la diferencia es ENORME! Dependiendo de la carga, verá números de rendimiento muy diferentes. Como menciona Darrel Miller, el HttpClient fue diseñado para ser reutilizado en todas las solicitudes. Esto fue confirmado por los chicos del equipo de BCL que lo escribieron.
Un proyecto reciente que tuve fue ayudar a un minorista informático en línea muy grande y conocido a escalar el tráfico del Viernes Negro / vacaciones para algunos sistemas nuevos. Nos encontramos con algunos problemas de rendimiento relacionados con el uso de HttpClient. Como se implementa
IDisposable, los desarrolladores hicieron lo que normalmente harían al crear una instancia y colocarla dentro de unausing()declaración. Una vez que comenzamos las pruebas de carga, la aplicación puso de rodillas al servidor; sí, el servidor no solo la aplicación. La razón es que cada instancia de HttpClient abre un puerto en el servidor. Debido a la finalización no determinista de GC y al hecho de que está trabajando con recursos informáticos que abarcan múltiples capas OSI , el cierre de puertos de red puede llevar un tiempo. De hecho, el propio sistema operativo WindowsPuede tomar hasta 20 segundos para cerrar un puerto (por Microsoft). Estábamos abriendo puertos más rápido de lo que podrían cerrarse: agotamiento del puerto del servidor que perjudicó la CPU al 100%. Mi solución fue cambiar el HttpClient a una instancia estática que resolvió el problema. Sí, es un recurso desechable, pero cualquier sobrecarga se ve ampliamente compensada por la diferencia en el rendimiento. Te animo a que hagas algunas pruebas de carga para ver cómo se comporta tu aplicación.También puede consultar la página de guía de WebAPI para obtener documentación y ejemplos en https://www.asp.net/web-api/overview/advanced/calling-a-web-api-from-a-net-client
Presta especial atención a esta llamada:
Si encuentra que necesita usar una estática
HttpClientcon diferentes encabezados, direcciones base, etc., lo que tendrá que hacer es crear elHttpRequestMessagemanual y establecer esos valores en elHttpRequestMessage. Luego, use elHttpClient:SendAsync(HttpRequestMessage requestMessage, ...)ACTUALIZACIÓN para .NET Core : debe usar la
IHttpClientFactoryinyección de dependencia vía para crearHttpClientinstancias. Administrará la vida útil por usted y no necesita deshacerse de él explícitamente. Consulte Realizar solicitudes HTTP utilizando IHttpClientFactory en ASP.NET Corefuente
Como dicen las otras respuestas,
HttpClientestá destinado a la reutilización. Sin embargo, la reutilización de una solaHttpClientinstancia en una aplicación multiproceso significa que no puede cambiar los valores de sus propiedades con estado, comoBaseAddressyDefaultRequestHeaders(por lo que solo puede usarlas si son constantes en su aplicación).Un enfoque para sortear esta limitación es envolver
HttpClientcon una clase que duplica todos losHttpClientmétodos que necesita (GetAsync,PostAsyncetc.) y los delega en un singletonHttpClient. Sin embargo, eso es bastante tedioso (también necesitará ajustar los métodos de extensión ), y afortunadamente hay otra forma : seguir creando nuevasHttpClientinstancias, pero reutilizando el subyacenteHttpClientHandler. Solo asegúrese de no desechar el controlador:fuente
SendAsynces mucho menos conveniente que los métodos dedicados comoPutAsync,PostAsJsonAsyncetc.Relacionado con sitios web de gran volumen pero no directamente con HttpClient. Tenemos el fragmento de código a continuación en todos nuestros servicios.
Desde https://msdn.microsoft.com/query/dev14.query?appId=Dev14IDEF1&l=EN-US&k=k(System.Net.ServicePoint.ConnectionLeaseTimeout);k(TargetFrameworkMoniker-.NETFramework,Version%3Dv4.5.2); k (DevLang-csharp) & rd = verdadero
"Puede usar esta propiedad para asegurarse de que las conexiones activas de un objeto de ServicePoint no permanezcan abiertas indefinidamente. Esta propiedad está destinada a escenarios en los que las conexiones deben interrumpirse y restablecerse periódicamente, como los escenarios de equilibrio de carga.
De manera predeterminada, cuando KeepAlive es verdadero para una solicitud, la propiedad MaxIdleTime establece el tiempo de espera para cerrar las conexiones de ServicePoint debido a la inactividad. Si ServicePoint tiene conexiones activas, MaxIdleTime no tiene efecto y las conexiones permanecen abiertas indefinidamente.
Cuando la propiedad ConnectionLeaseTimeout se establece en un valor distinto de -1, y después de que transcurre el tiempo especificado, se cierra una conexión de ServicePoint activa después de atender una solicitud estableciendo KeepAlive en falso en esa solicitud. Establecer este valor afecta a todas las conexiones administradas por el objeto ServicePoint ".
Cuando tiene servicios detrás de un CDN u otro punto final que desea conmutar por error, esta configuración ayuda a las personas que llaman a seguirlo a su nuevo destino. En este ejemplo, 60 segundos después de una conmutación por error, todas las personas que llaman deben volver a conectarse al nuevo punto final. Requiere que conozca sus servicios dependientes (aquellos servicios que USTED llama) y sus puntos finales.
fuente
También puede consultar esta publicación de blog de Simon Timms: https://aspnetmonsters.com/2016/08/2016-08-27-httpclientwrong/
fuente
Una cosa para señalar, que ninguno de los blogs de "no usar usando" nota es que no es solo la BaseAddress y DefaultHeader lo que debe tener en cuenta. Una vez que hace que HttpClient sea estático, hay estados internos que se llevarán a través de las solicitudes. Un ejemplo: se está autenticando a un tercero con HttpClient para obtener un token FedAuth (ignore por qué no usa OAuth / OWIN / etc.), ese mensaje de Respuesta tiene un encabezado Set-Cookie para FedAuth, esto se agrega a su estado HttpClient. El siguiente usuario que inicie sesión en su API enviará la cookie FedAuth de la última persona a menos que esté administrando estas cookies en cada solicitud.
fuente
Como primer problema, aunque esta clase es desechable, usarla con la
usinginstrucción no es la mejor opción porque incluso cuando desecha elHttpClientobjeto, el socket subyacente no se libera de inmediato y puede causar un problema grave llamado 'agotamiento de sockets'.Pero hay un segundo problema
HttpClientque puede tener cuando lo usa como objeto único o estático. En este caso, un singleton o staticHttpClientno respeta losDNScambios.en .net core puedes hacer lo mismo con HttpClientFactory algo como esto:
Configurar servicios
documentación y ejemplo aquí
fuente