Dirk Richter
Software-Entwicklung und Architektur
Nutzung des HttpClient in NET 8 und core
Im .NET Framework 4.8 und .NET 8 gibt es deutliche Unterschiede in der Nutzung vom Wiederverwendung vom oder innerhalb einer HttpClientWrapper Klasse, die als Singleton instanziiert ist. Vermeiden von ‘using’ statt IDiposable: Lebenszyklus- und Pooling-Verwaltung: Verwendung von Statt Lebensdauer und Pipelining konfigurieren: Die Lebensdauer von Verbindungen und DNS-Caches kann im
Inhaltsverzeichnis
Unterschiede zwischen der korrekten Nutzung des HttpClient in .NET 4.8 und .NET 8
HttpClient
und den zugehörigen Handler, insbesondere in Hinblick auf ‘Disposing’ und die Vermeidung von ‘Socket Exhaustion’. Im Folgenden werden beide Umgebungen miteinander verglichen.
Wichtige Konzepte
HttpClient
: Eine High-Level-Klasse zum Versenden von HTTP-Anfragen und Empfangen von HTTP-Antworten.HttpClientHandler
: Eine Low-Level-Klasse, die für die Verwaltung von HTTP-Verbindungen, Sockets und Transport-Layer-Details zuständig ist.
.NET Framework 4.8
Herausforderungen
HttpClient
erstellt wird, wird auch ein neuer HttpClientHandler
zugewiesen. Da der Handler für die Sockets zuständig ist, führt häufiges Erstellen und Freigeben von HttpClient
-Instanzen zu einer Erschöpfung der Sockets (z. B. durch das Erreichen der TCP/IP-Verbindungslimits).HttpClient
korrekt ‘disposed’ wird, bleiben die darunterliegenden Sockets im TCP/IP-Stack unter Umständen im TIME_WAIT
-Status, was die Wiederverwendung erschwert.Best Practices
HttpClient
:
HttpClient
sollte über den gesamten Lebenszyklus der Anwendung hinweg wiederverwendet werden, statt jedes Mal eine neue zu erstellen. Dies reduziert den Overhead und verhindert Socket-Erschöpfung.
Als ‘static’: 1public class HttpClientWrapper
2{
3 private static readonly HttpClient _httpClient;
4 static HttpClientWrapper()
5 {
6 _httpClient = new HttpClient
7 {
8 Timeout = TimeSpan.FromSeconds(30) // Optional: Timeout setzen
9 };
10 }
11
12 public static HttpClient Instance => _httpClient;
13}
1 public HttpClientWrapper()
2 {
3 _handler = new HttpClientHandler();
4 _httpClient = new HttpClient(_handler);
5 }
6 ```
Dispose()
eines HttpClient
wird der darunterliegende HttpClientHandler
ebenfalls geschlossen, wodurch die Sockets im TIME_WAIT
-Status bleiben. Dies kann zu einer Erschöpfung der verfügbaren TCP/IP-Verbindungen führen, insbesondere bei kurzen, häufigen Anfragen.
Nicht(!) verwenden:
1using (HttpClient client = new HttpClient())
2{
3 var response = await client.GetAsync("https://example.com");
4}
Einschränkungen
HttpClient
-Instanzen. Entwickler müssen selbst sicherstellen, dass dieser korrekt verwendet wird, was zusätzlichen Aufwand bedeutet.
.NET 8
Verbesserungen
HttpClientFactory
:
IHttpClientFactory
-Feature eingeführt. Es dient zur Verwaltung von HttpClient
-Instanzen und deren Handlers, um Probleme wie Socket-Erschöpfung zu vermeiden.IHttpClientFactory
sorgt dafür, dass Handlers und Verbindungen nicht zu häufig erstellt und korrekt freigegeben werden.1services.AddHttpClient(); // Konfiguration in der ServiceCollection
SocketsHttpHandler
:
SocketsHttpHandler
den HttpClientHandler
als Standard-Handler.
HttpClientFactory
bietet Out-of-the-Box Unterstützung für Pooling sowie das automatische Verwerfen und Revalidieren von Verbindungen ohne, dass Verbindungen in den TIME_WAIT
-Zustand gleiten.Best Practices (für .NET 8)
IHttpClientFactory
:
HttpClient
-Instanzen manuell zu erstellen oder zu verwalten, sollte das IHttpClientFactory
verwendet werden, um das Disposing und die Wiederverwendung zu automatisieren. 1public class MyService
2{
3 private readonly HttpClient _httpClient;
4
5 public MyService(HttpClient httpClient)
6 {
7 _httpClient = httpClient;
8 }
9
10 public async Task<string> GetSomething()
11 {
12 var response = await _httpClient.GetStringAsync("https://example.com");
13 return response;
14 }
15}
IHttpClientFactory
mit eigener Konfiguration angepasst werden.1services.AddHttpClient("MyNamedClient")
2 .SetHandlerLifetime(TimeSpan.FromMinutes(5)) // Handler nach 5 Minuten neu erstellen
3 .AddPolicyHandler(Polly.Policy.TimeoutAsync<HttpResponseMessage>(TimeSpan.FromSeconds(10)));
Korrektes ‘Disposen’
.NET Framework 4.8
HttpClient
-Instanzen sollten möglichst wenig verwendet werden. Stattdessen sollte eine einzige Instanz über die Lebensdauer der Anwendung hinweg genutzt werden..NET 8
IHttpClientFactory
wird die Verwaltung von Handlers und deren Lebenszyklen größtenteils automatisiert. Der manuelle Umgang mit Disposal entfällt.SocketsHttpHandler
reduziert den Verwaltungsaufwand durch besseres Pooling und Lebenszyklusmanagement.
Unterschiede zusammengefasst
Feature
.NET Framework 4.8
.NET 8
Standard-Handler
HttpClientHandler
SocketsHttpHandler
Factory (Lebenszyklus automatisch)
Nicht verfügbar
Ja (
IHttpClientFactory
)
Problem: Socket-Erschöpfung
Manuelle Wiederverwendung erforderlich
Automatisch durch
HttpClientFactory
DNS-Caching
Manuelle Implementierung umständlich
Eingebaut und leicht konfigurierbar
Connection-Pooling
Begrenzt und ineffizient
Effizient via
SocketsHttpHandler
Disposing
Manuell erforderlich
Automatisch bei Verwendung von Factory
Fazit
HttpClient
-Instanzen müssen wiederverwendet werden, um Socket-Erschöpfung zu vermeiden, und Handlers sollten manuell korrekt freigegeben werden.IHttpClientFactory
und SocketsHttpHandler
ist der empfohlene Ansatz. Dies automatisiert das Ressourcen- und Verbindungsmanagement und verbessert die Performance deutlich.