HttpClientFactory usa SocketsHttpHandler como manipulador primário
HttpClientFactory
Permite configurar um HttpMessageHandler pipeline para objetos nomeados e digitados HttpClient . O manipulador mais interno, ou aquele que realmente envia a solicitação no fio, é chamado de manipulador primário. Se não estiver configurado, esse manipulador anteriormente sempre foi um HttpClientHandlerarquivo . 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 o suportam. Em outras plataformas, por exemplo, o .NET Framework HttpClientHandler continua a ser usado.
SocketsHttpHandler
Agora também tem a PooledConnectionLifetime propriedade predefinida para corresponder ao HandlerLifetime valor. (Ele reflete o valor mais recente, se HandlerLifetime
foi configurado pelo usuário).
Versão introduzida
.NET 9 Visualização 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
Em plataformas onde SocketsHttpHandler
é suportado, o manipulador primário padrão agora SocketsHttpHandler
está com PooledConnectionLifetime
definido para o HandlerLifetime
valor. Convertê-lo para HttpClientHandler
atualizar as propriedades lança um InvalidCastExceptionarquivo .
Por exemplo, o mesmo código da seção Comportamento anterior agora lança um InvalidCastException:
System.InvalidCastException: Não é possível converter objeto do tipo 'System.Net.Http.SocketsHttpHandler' para digitar 'System.Net.Http.HttpClientHandler'.
Tipo de mudança de rutura
Esta mudança é uma mudança comportamental.
Razão para a alteração
Um dos problemas HttpClientFactory
mais comuns que os usuários enfrentam é quando um Named
ou Typed
cliente erroneamente é capturado em um serviço singleton ou, em geral, armazenado em algum lugar por um período de tempo maior do que o especificado 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 SocketsHttpHandler, que tem uma opção para controlar PooledConnectionLifetime. 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 mais baixo. 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 se certificar de que HttpClient
não é 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 errôneos — 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)).
Ação recomendada
Há três opções para contornar a mudança de rutura:
Especifique e configure explicitamente um manipulador primário para cada um dos 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á ambos
HttpClientHandler
eSocketsHttpHandler
:services.AddHttpClient("test") .ConfigurePrimaryHttpMessageHandler((h, _) => { if (h is HttpClientHandler hch) { hch.UseCookies = false; } if (h is SocketsHttpHandler shh) { shh.UseCookies = false; } });