Compartir vía


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

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

API afectadas