Entonces, la pregunta es ¿por qué el uso de HttpClient al usar el bloque es INCORRECTO, PERO en el contexto de WebApi?
He estado leyendo este artículo No bloquear en código asíncrono . En él tenemos el siguiente ejemplo:
public static async Task<JObject> GetJsonAsync(Uri uri) { // (real-world code shouldn't use HttpClient in a using block; this is just example code) using (var client = new HttpClient()) { var jsonString = await client.GetStringAsync(uri); return JObject.Parse(jsonString); } } // My "top-level" method. public class MyController : ApiController { public string Get() { var jsonTask = GetJsonAsync(...); return jsonTask.Result.ToString(); } } El comentario // (real-world code shouldn't use HttpClient in a using block; this is just example code) me disparó. Siempre he estado usando HttpClient de esta manera.
Lo siguiente que revisé es la documentación de Microsoft sobre HttpClient Class . En él, tenemos la siguiente declaración con la fuente de muestra provista:
HttpClient está diseñado para ser instanciado una vez y reutilizado a lo largo de la vida de una aplicación. Crear instancias de una clase HttpClient para cada solicitud agotará la cantidad de sockets disponibles bajo cargas pesadas. Esto dará como resultado errores de SocketException. A continuación se muestra un ejemplo que usa HttpClient correctamente.
public class GoodController : ApiController { private static readonly HttpClient HttpClient; static GoodController() { HttpClient = new HttpClient(); } }Entonces, ¿no se llama al constructor en cada solicitud y, por lo tanto, se creará un nuevo HttpClient cada vez?
¡Gracias!
Hay una respuesta un poco larga para esto...
Originalmente, la recomendación oficial era usar HttpClient en un bloque de using . Pero esto causó problemas a escala , esencialmente consumiendo muchas conexiones en el estado TIME_WAIT .
Entonces, la recomendación oficial cambió para usar un HttpClient estático. Pero esto causó problemas en los que nunca manejaría correctamente las actualizaciones de DNS .
Entonces, el equipo de ASP.NET ideó IHttpClientFactory en .NET Core 2.1 , por lo que el código (o al menos el código que se ejecuta en plataformas modernas) puede reutilizar las instancias de HttpClient (o, más correctamente, los controladores de mensajes de esas instancias), evitando el TIME_WAIT problema, pero también cerrando periódicamente esas conexiones para evitar el problema de DNS.
Pero, al mismo tiempo, el equipo de .NET ideó SocketsHttpHandler también en .NET Core 2.1 , que también realiza la agrupación de conexiones.
Por lo tanto, en las plataformas modernas, puede usar IHttpClientFactory o un HttpClient estático/singleton. En plataformas más antiguas (incluido .NET Framework), usaría un HttpClient estático/singleton y viviría con el problema de DNS o usaría otras soluciones alternativas .
En realidad, al escribir esta pregunta, noté el constructor estático en el ejemplo de código proporcionado por Microsoft. Todo esto tiene sentido ahora.
Los constructores estáticos se utilizan para inicializar cualquier dato estático o para realizar una acción particular que debe realizarse solo una vez. Se llama automáticamente antes de que se cree la primera instancia o se haga referencia a cualquier miembro estático.
En el contexto de WebAPI, el constructor estático se llama una sola vez , por lo que se crea solo un HttpClient y se reutiliza para todas las demás solicitudes.
Nunca volveré a usar using(HttpClient....) en el código de producción.
Este es un gran artículo sobre el uso incorrecto de HttpClient - ESTÁS UTILIZANDO HTTPCLIENT MAL Y ESTÁ DESESTABILIZANDO TU SOFTWARE