Condividi tramite


HttpClientFactory usa SocketsHttpHandler come gestore primario

HttpClientFactory consente di configurare una HttpMessageHandler pipeline per oggetti denominati e tipizzati HttpClient . Il gestore più interno, o quello che invia effettivamente la richiesta in transito, è denominato gestore primario. Se non è configurato, questo gestore era sempre un oggetto HttpClientHandler. Mentre il gestore primario predefinito è un dettaglio di implementazione, c'erano utenti che ne dipendevano. Ad esempio, alcuni utenti esegue il cast del gestore primario per HttpClientHandler impostare proprietà come ClientCertificates, UseCookiese UseProxy.

Con questa modifica, il gestore primario predefinito è un oggetto SocketsHttpHandler sulle piattaforme che lo supportano. In altre piattaforme, ad esempio .NET Framework, HttpClientHandler continua a essere usato.

SocketsHttpHandler ora ha anche la PooledConnectionLifetime proprietà preimpostata in modo che corrisponda al HandlerLifetime valore. (riflette il valore più recente, se HandlerLifetime è stato configurato dall'utente).

Versione introdotta

.NET 9 Anteprima 6

Comportamento precedente

Il gestore primario predefinito è .HttpClientHandler Eseguire il cast per HttpClientHandler aggiornare le proprietà è stato eseguito correttamente.

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

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

Nuovo comportamento

Nelle piattaforme in cui SocketsHttpHandler è supportato il gestore primario predefinito è ora SocketsHttpHandler impostato PooledConnectionLifetime sul HandlerLifetime valore . Eseguire il cast per HttpClientHandler aggiornare le proprietà genera un'eccezione InvalidCastException.

Ad esempio, lo stesso codice della sezione Comportamento precedente genera ora un'eccezione InvalidCastException:

System.InvalidCastException: impossibile eseguire il cast dell'oggetto di tipo 'System.Net.Http.SocketsHttpHandler' per digitare 'System.Net.Http.HttpClientHandler'.

Tipo di modifica che causa un'interruzione

Questa è una modifica funzionale.

Motivo della modifica

Uno dei problemi HttpClientFactory più comuni riscontrati dagli utenti è quando un Named client o Typed viene erroneamente acquisito in un servizio singleton o, in generale, archiviato in un punto per un periodo di tempo maggiore rispetto a quello specificato HandlerLifetime. Poiché HttpClientFactory non è possibile ruotare tali gestori, potrebbero non rispettare le modifiche DNS.

Questo problema può essere risolto usando SocketsHttpHandler, che dispone di un'opzione per controllare PooledConnectionLifetime. Analogamente a HandlerLifetime, la durata della connessione in pool consente di ricreare regolarmente le connessioni per raccogliere le modifiche DNS, ma a un livello inferiore. Un client con PooledConnectionLifetime configurazione può essere usato in modo sicuro come singleton.

Purtroppo, è facile e apparentemente "intuitivo" inserire un Typed client in un singleton. Ma è difficile avere qualsiasi tipo di controllo o analizzatore per assicurarsi HttpClient che non venga acquisito quando non doveva essere acquisito. È anche difficile risolvere i problemi risultanti. Pertanto, come misura preventiva, per ridurre al minimo il potenziale impatto dei modelli di utilizzo errati, la SocketsHttpHandler mitigazione viene ora applicata per impostazione predefinita.

Questa modifica influisce solo sui casi in cui il client non è stato configurato dall'utente finale per l'uso di un personalizzato PrimaryHandler ,ad esempio tramite ConfigurePrimaryHttpMessageHandler<THandler>(IHttpClientBuilder).

Esistono tre opzioni per aggirare la modifica che causa un'interruzione:

  • Specificare e configurare in modo esplicito un gestore primario per ognuno dei client:

    services.AddHttpClient("test")
      .ConfigurePrimaryHttpMessageHandler(() => new HttpClientHandler() { UseCookies = false });
    
  • Sovrascrivere il gestore primario predefinito per tutti i client usando ConfigureHttpClientDefaults(IServiceCollection, Action<IHttpClientBuilder>):

    services.ConfigureHttpClientDefaults(b =>
      b.ConfigurePrimaryHttpMessageHandler(() => new HttpClientHandler() { UseCookies = false }));
    
  • Nell'azione di configurazione verificare sia che HttpClientHandler SocketsHttpHandler:

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

API interessate