HttpClientFactory usa SocketsHttpHandler como controlador principal
HttpClientFactory
permite configurar una HttpMessageHandler canalización para objetos con nombre y con HttpClient tipo. El controlador más interno, o el que realmente envía la solicitud en la conexión, se denomina controlador principal. Si no está configurado, este controlador siempre era un HttpClientHandler. Aunque el controlador principal predeterminado es un detalle de implementación, había usuarios que dependían de él. Por ejemplo, algunos usuarios convierten el controlador principal en HttpClientHandler
para establecer propiedades como ClientCertificates, UseCookiesy UseProxy.
Con este cambio, el controlador principal predeterminado es en SocketsHttpHandler plataformas que lo admiten. En otras plataformas, por ejemplo, .NET Framework, HttpClientHandler se sigue usando.
SocketsHttpHandler
ahora también tiene el valor preestablecido de la PooledConnectionLifetime propiedad para que coincida con el HandlerLifetime valor. (Refleja el valor más reciente, si HandlerLifetime
el usuario lo configuró).
Versión introducida
.NET 9, versión preliminar 6
Comportamiento anterior
El controlador principal predeterminado era HttpClientHandler
. La conversión a HttpClientHandler
para actualizar las propiedades ha funcionado.
services.AddHttpClient("test")
.ConfigurePrimaryHttpMessageHandler((h, _) =>
{
((HttpClientHandler)h).UseCookies = false;
});
// This worked.
var client = httpClientFactory.CreateClient("test");
Comportamiento nuevo
En las plataformas en SocketsHttpHandler
las que se admite, el controlador principal predeterminado ahora SocketsHttpHandler
está establecido en PooledConnectionLifetime
el HandlerLifetime
valor . La conversión a HttpClientHandler
para actualizar las propiedades produce una InvalidCastExceptionexcepción .
Por ejemplo, el mismo código de la sección Comportamiento anterior ahora produce un InvalidCastException:
System.InvalidCastException: no se puede convertir el objeto de tipo "System.Net.Http.SocketsHttpHandler" al tipo "System.Net.Http.HttpClientHandler".
Tipo de cambio importante
Este es un cambio de funcionamiento.
Motivo del cambio
Uno de los problemas HttpClientFactory
más comunes en los que se encuentran los usuarios es cuando un Named
cliente o Typed
se captura erróneamente en un servicio singleton, o, en general, se almacena en algún lugar durante un período de tiempo mayor que el especificado HandlerLifetime. Dado HttpClientFactory
que no puede rotar estos controladores, es posible que terminen sin respetar los cambios de DNS.
Este problema se puede mitigar mediante SocketsHttpHandler, que tiene una opción para controlar PooledConnectionLifetime. De forma similar a HandlerLifetime, la duración de la conexión agrupada permite volver a crear conexiones periódicamente para recoger los cambios de DNS, pero en un nivel inferior. Un cliente con PooledConnectionLifetime
configuración se puede usar de forma segura como singleton.
Es, desafortunadamente, fácil y aparentemente "intuitivo" insertar un Typed
cliente en un singleton. Pero es difícil tener ningún tipo de comprobación o analizador para asegurarse HttpClient
de que no se captura cuando no se supone que se ha capturado. También es difícil solucionar los problemas resultantes. Por lo tanto, como medida preventiva , para minimizar el posible impacto de los patrones de uso erróneos, la SocketsHttpHandler
mitigación ahora se aplica de forma predeterminada.
Este cambio solo afecta a los casos en los que el usuario final no configuró el cliente para usar un personalizado PrimaryHandler (por ejemplo, a través de ConfigurePrimaryHttpMessageHandler<THandler>(IHttpClientBuilder)).
Acción recomendada
Hay tres opciones para solucionar el cambio importante:
Especifique y configure explícitamente un controlador principal para cada uno de los clientes:
services.AddHttpClient("test") .ConfigurePrimaryHttpMessageHandler(() => new HttpClientHandler() { UseCookies = false });
Sobrescriba el controlador principal predeterminado para todos los clientes que usan ConfigureHttpClientDefaults(IServiceCollection, Action<IHttpClientBuilder>):
services.ConfigureHttpClientDefaults(b => b.ConfigurePrimaryHttpMessageHandler(() => new HttpClientHandler() { UseCookies = false }));
En la acción de configuración, compruebe si hay y
HttpClientHandler
SocketsHttpHandler
:services.AddHttpClient("test") .ConfigurePrimaryHttpMessageHandler((h, _) => { if (h is HttpClientHandler hch) { hch.UseCookies = false; } if (h is SocketsHttpHandler shh) { shh.UseCookies = false; } });