Compartilhar via


HttpClientFactory usa SocketsHttpHandler como manipulador primário

HttpClientFactory Permite configurar um HttpMessageHandler pipeline para objetos nomeados e tipados HttpClient . O manipulador mais interno, ou aquele que realmente envia a solicitação na transmissão, é chamado de manipulador primário. Se não estiver configurado, esse manipulador era sempre um HttpClientHandler. Embora o manipulador primário padrão seja um detalhe de implementação, havia usuários que dependiam dele. Por exemplo, alguns usuários convertem o manipulador primário para HttpClientHandler definir propriedades como ClientCertificates, UseCookiese UseProxy.

Com essa alteração, o manipulador primário padrão é um SocketsHttpHandler em plataformas que dão suporte a ele. Em outras plataformas, por exemplo, o .NET Framework HttpClientHandler continua a ser usado.

SocketsHttpHandler agora também tem a predefinição de PooledConnectionLifetime propriedade para corresponder HandlerLifetime ao valor. (Reflete o valor mais recente, se HandlerLifetime foi configurado pelo usuário).

Versão introduzida

.NET 9 Preview 6

Comportamento anterior

O manipulador primário padrão era HttpClientHandler. Transmiti-lo para HttpClientHandler atualizar as propriedades funcionou.

services.AddHttpClient("test")
    .ConfigurePrimaryHttpMessageHandler((h, _) =>
    {
        ((HttpClientHandler)h).UseCookies = false;
    });

// This worked.
var client = httpClientFactory.CreateClient("test");

Novo comportamento

Nas plataformas em que SocketsHttpHandler há suporte, o manipulador primário padrão agora SocketsHttpHandler PooledConnectionLifetime é set como o HandlerLifetime valor. Convertê-lo para HttpClientHandler atualizar as propriedades gera um InvalidCastException.

Por exemplo, o mesmo código da seção Comportamento anterior agora lança um InvalidCastException:

System.InvalidCastException: não é possível converter o objeto do tipo 'System.Net.Http.SocketsHttpHandler' para o tipo 'System.Net.Http.HttpClientHandler'.

Tipo de alteração interruptiva

Esta é uma alteração comportamental.

Motivo da alteração

Um dos problemas HttpClientFactory mais comuns que os usuários enfrentam é quando um Named cliente ou Typed é capturado erroneamente em um serviço singleton ou, em geral, armazenado em algum lugar por um período de tempo maior do que o .HandlerLifetime Como HttpClientFactory não é possível girar esses manipuladores, eles podem acabar não respeitando as alterações de DNS.

Esse problema pode ser atenuado usando SocketsHttpHandlero , que tem uma opção para controlar PooledConnectionLifetimeo . Da mesma forma que o HandlerLifetime, o tempo de vida da conexão em pool permite recriar regularmente conexões para captar alterações de DNS, mas em um nível inferior. Um cliente com PooledConnectionLifetime configuração pode ser usado com segurança como um singleton.

Infelizmente, é fácil e aparentemente "intuitivo" injetar um Typed cliente em um singleton. Mas é difícil ter qualquer tipo de verificação ou analisador para garantir que HttpClient não seja capturado quando não deveria ser capturado. Também é difícil solucionar os problemas resultantes. Portanto, como medida preventiva, para minimizar o impacto potencial de padrões de uso incorretos, a SocketsHttpHandler mitigação agora é aplicada por padrão.

Essa alteração afeta apenas os casos em que o cliente não foi configurado pelo usuário final para usar um personalizado PrimaryHandler (por exemplo, via ConfigurePrimaryHttpMessageHandler<THandler>(IHttpClientBuilder)).

Há três opções para contornar a alteração significativa:

  • Especifique e configure explicitamente um manipulador primário para cada um de seus clientes:

    services.AddHttpClient("test")
      .ConfigurePrimaryHttpMessageHandler(() => new HttpClientHandler() { UseCookies = false });
    
  • Substitua o manipulador primário padrão para todos os clientes usando ConfigureHttpClientDefaults(IServiceCollection, Action<IHttpClientBuilder>):

    services.ConfigureHttpClientDefaults(b =>
      b.ConfigurePrimaryHttpMessageHandler(() => new HttpClientHandler() { UseCookies = false }));
    
  • Na ação de configuração, verifique se há e HttpClientHandler SocketsHttpHandler:

    services.AddHttpClient("test")
      .ConfigurePrimaryHttpMessageHandler((h, _) =>
      {
          if (h is HttpClientHandler hch)
          {
              hch.UseCookies = false;
          }
    
          if (h is SocketsHttpHandler shh)
          {
              shh.UseCookies = false;
          }
      });
    

APIs afetadas