Ereignisse
17. März, 21 Uhr - 21. März, 10 Uhr
Nehmen Sie an der Meetup-Serie teil, um skalierbare KI-Lösungen basierend auf realen Anwendungsfällen mit Mitentwicklern und Experten zu erstellen.
Jetzt registrierenDieser Browser wird nicht mehr unterstützt.
Führen Sie ein Upgrade auf Microsoft Edge durch, um die neuesten Features, Sicherheitsupdates und den technischen Support zu nutzen.
In diesem Artikel erfahren Sie, wie Sie mit der IHttpClientFactory
-Schnittstelle HttpClient
-Typen mit verschiedenen .NET-Grundlagen wie Dependency Injection (DI), Protokollierung und Konfiguration erstellen können. Der HttpClient-Typ wurde in .NET Framework 4.5 eingeführt, das 2012 veröffentlicht wurde. Anders ausgedrückt: Ihn gibt es schon eine Weile. HttpClient
wird zum Senden von HTTP-Anforderungen und zum Behandeln von HTTP-Antworten von Webressourcen verwendet, die von einem Uri identifiziert werden. Das HTTP-Protokoll macht den Großteil des Internetdatenverkehrs aus.
Mit modernen Anwendungsentwicklungsprinzipien, die bewährte Methoden fördern, dient IHttpClientFactory als Factoryabstraktion, die HttpClient
-Instanzen mit benutzerdefinierten Konfigurationen erstellen kann. IHttpClientFactory wurde in .NET Core 2.1 eingeführt. Gängige HTTP-basierte .NET-Workloads können die Resilienz und die Behandlung vorübergehender Fehler von Drittanbieter-Middleware problemlos nutzen.
Hinweis
Wenn Ihre App Cookies benötigt, ist es möglicherweise besser, die Verwendung von IHttpClientFactory in Ihrer App zu vermeiden. Alternative Methoden zum Verwalten von Clients finden Sie unter Richtlinien für die Verwendung von HTTP-Clients.
Wichtig
Die Lebensdauerverwaltung von HttpClient
-Instanzen, die von IHttpClientFactory
erstellt werden, unterscheidet sich vollständig von manuell erstellten Instanzen. Die Strategien sind die Verwendung kurzlebiger Clients, die von IHttpClientFactory
erstellt werden, oder langlebiger Clients, für die PooledConnectionLifetime
eingerichtet ist. Weitere Informationen finden Sie im Abschnitt HttpClient-Lebensdauerverwaltung und Richtlinien für die Verwendung von HTTP-Clients.
Für den gesamten in diesem Artikel bereitgestellten Beispielquellcode ist die Installation des Microsoft.Extensions.Http
NuGet-Pakets erforderlich. Darüber hinaus veranschaulichen die Codebeispiele die Verwendung von HTTP-GET
Anforderungen zum Abrufen von BenutzerobjektenTodo
aus der kostenlosen {JSON}-Platzhalter-API.
Wenn Sie eine der AddHttpClient-Erweiterungsmethoden aufrufen, fügen Sie die IHttpClientFactory
und zugehörige Dienste der IServiceCollection hinzu. Der IHttpClientFactory
-Typ bietet folgende Vorteile:
HttpClient
-Klasse als DI-bereiten Typ verfügbar.HttpClient
-Instanzen wird damit geboten.HttpClient
in Code umgesetzt.HttpClient
zu nutzen.HttpClient
auftreten.Es gibt mehrere Möglichkeiten IHttpClientFactory
in einer App zu verwenden:
Der beste Ansatz richtet sich nach den Anforderungen der App.
Um die IHttpClientFactory
zu registrieren, rufen Sie den AddHttpClient
auf:
using Shared;
using BasicHttp.Example;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging;
HostApplicationBuilder builder = Host.CreateApplicationBuilder(args);
builder.Services.AddHttpClient();
builder.Services.AddTransient<TodoService>();
using IHost host = builder.Build();
Das Nutzen von Diensten kann die IHttpClientFactory
als Konstruktorparameter mit DI erfordern. Im folgenden Code wird IHttpClientFactory
verwendet, um eine HttpClient
-Instanz zu erstellen:
using System.Net.Http.Json;
using System.Text.Json;
using Microsoft.Extensions.Logging;
using Shared;
namespace BasicHttp.Example;
public sealed class TodoService(
IHttpClientFactory httpClientFactory,
ILogger<TodoService> logger)
{
public async Task<Todo[]> GetUserTodosAsync(int userId)
{
// Create the client
using HttpClient client = httpClientFactory.CreateClient();
try
{
// Make HTTP GET request
// Parse JSON response deserialize into Todo types
Todo[]? todos = await client.GetFromJsonAsync<Todo[]>(
$"https://jsonplaceholder.typicode.com/todos?userId={userId}",
new JsonSerializerOptions(JsonSerializerDefaults.Web));
return todos ?? [];
}
catch (Exception ex)
{
logger.LogError("Error getting something fun to say: {Error}", ex);
}
return [];
}
}
IHttpClientFactory
wie im vorhergehenden Beispiel zu verwenden ist eine gute Möglichkeit zum Umgestalten einer vorhandene App. Dies hat keine Auswirkung auf die Verwendung von HttpClient
. An Stellen, an denen HttpClient
-Instanzen in einer vorhandenen App erstellt werden, können Sie diese Ereignisse mit Aufrufen von CreateClient ersetzen.
Benannte Clients sind in folgenden Fällen eine gute Wahl:
HttpClient
.HttpClient
-Instanzen haben unterschiedliche Konfigurationen.Die Konfiguration eines benannten HttpClient
kann während der Registrierung in der IServiceCollection
angegeben werden:
using Shared;
using NamedHttp.Example;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging;
HostApplicationBuilder builder = Host.CreateApplicationBuilder(args);
string? httpClientName = builder.Configuration["TodoHttpClientName"];
ArgumentException.ThrowIfNullOrEmpty(httpClientName);
builder.Services.AddHttpClient(
httpClientName,
client =>
{
// Set the base address of the named client.
client.BaseAddress = new Uri("https://jsonplaceholder.typicode.com/");
// Add a user-agent default request header.
client.DefaultRequestHeaders.UserAgent.ParseAdd("dotnet-docs");
});
Im vorangehenden Code wird der Client mit Folgendem konfiguriert:
"TodoHttpClientName"
gezogen wird.https://jsonplaceholder.typicode.com/
"User-Agent"
-Header.Sie können die Konfiguration verwenden, um HTTP-Clientnamen anzugeben. Dies ist hilfreich, um eine falsche Clientbenennung beim Hinzufügen und Erstellen zu vermeiden. In diesem Beispiel wird die Datei appsettings.json verwendet, um den HTTP-Clientnamen zu konfigurieren:
{
"TodoHttpClientName": "JsonPlaceholderApi"
}
Es ist einfach, diese Konfiguration zu erweitern und weitere Details zur gewünschten Funktionsweise Ihres HTTP-Clients zu speichern. Weitere Informationen finden Sie unter Konfiguration in .NET.
Jedes Mal, wenn CreateClient aufgerufen wird, geschieht Folgendes:
HttpClient
wird erstellt.Übergeben Sie für die Erstellung eines benannten Clients dessen Namen an CreateClient
:
using System.Net.Http.Json;
using System.Text.Json;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.Logging;
using Shared;
namespace NamedHttp.Example;
public sealed class TodoService
{
private readonly IHttpClientFactory _httpClientFactory = null!;
private readonly IConfiguration _configuration = null!;
private readonly ILogger<TodoService> _logger = null!;
public TodoService(
IHttpClientFactory httpClientFactory,
IConfiguration configuration,
ILogger<TodoService> logger) =>
(_httpClientFactory, _configuration, _logger) =
(httpClientFactory, configuration, logger);
public async Task<Todo[]> GetUserTodosAsync(int userId)
{
// Create the client
string? httpClientName = _configuration["TodoHttpClientName"];
using HttpClient client = _httpClientFactory.CreateClient(httpClientName ?? "");
try
{
// Make HTTP GET request
// Parse JSON response deserialize into Todo type
Todo[]? todos = await client.GetFromJsonAsync<Todo[]>(
$"todos?userId={userId}",
new JsonSerializerOptions(JsonSerializerDefaults.Web));
return todos ?? [];
}
catch (Exception ex)
{
_logger.LogError("Error getting something fun to say: {Error}", ex);
}
return [];
}
}
Im vorangehenden Code muss die HTTP-Anforderung keinen Hostnamen angeben. Der Code muss nur den Pfad übergeben, da die für den Client konfigurierte Basisadresse verwendet wird.
Typisierte Clients:
HttpClient
bereit. Beispielsweise kann ein einzelner typisierter Client für Folgendes verwendet werden: Ein typisierter Client akzeptiert einen HttpClient
-Parameter in seinem Konstruktor:
using System.Net.Http.Json;
using System.Text.Json;
using Microsoft.Extensions.Logging;
using Shared;
namespace TypedHttp.Example;
public sealed class TodoService(
HttpClient httpClient,
ILogger<TodoService> logger) : IDisposable
{
public async Task<Todo[]> GetUserTodosAsync(int userId)
{
try
{
// Make HTTP GET request
// Parse JSON response deserialize into Todo type
Todo[]? todos = await httpClient.GetFromJsonAsync<Todo[]>(
$"todos?userId={userId}",
new JsonSerializerOptions(JsonSerializerDefaults.Web));
return todos ?? [];
}
catch (Exception ex)
{
logger.LogError("Error getting something fun to say: {Error}", ex);
}
return [];
}
public void Dispose() => httpClient?.Dispose();
}
Für den Code oben gilt:
HttpClient
wird als Variable im Klassenbereich (Feld) zugewiesen und mit verfügbar gemachten APIs verwendet.Es können API-spezifische Methoden erstellt werden, die die HttpClient
-Funktionalität verfügbar machen. Die GetUserTodosAsync
-Methode kapselt z. B. Code zum Abrufen von benutzerspezifischen Todo
-Objekten.
Der folgende Code ruft AddHttpClient auf, um eine typisierte Clientklasse zu registrieren:
using Shared;
using TypedHttp.Example;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging;
HostApplicationBuilder builder = Host.CreateApplicationBuilder(args);
builder.Services.AddHttpClient<TodoService>(
client =>
{
// Set the base address of the typed client.
client.BaseAddress = new Uri("https://jsonplaceholder.typicode.com/");
// Add a user-agent default request header.
client.DefaultRequestHeaders.UserAgent.ParseAdd("dotnet-docs");
});
Der typisierte Client wird mit DI als „vorübergehend“ registriert. Im vorherigen Code registriert AddHttpClient
TodoService
als vorübergehenden Dienst. Diese Registrierung verwendet eine Factorymethode für folgende Aktionen:
HttpClient
:TodoService
-Instanz, wobei die Instanz von HttpClient
an ihren Konstrukt übergeben wirdWichtig
Die Verwendung von typisierten Clients in Singleton-Diensten kann gefährlich sein. Weitere Informationen finden Sie im Abschnitt Vermeiden von typisierten Clients in Singleton-Diensten.
Hinweis
Beim Registrieren eines typisierten Clients mit der AddHttpClient<TClient>
-Methode muss der TClient
-Typ über einen Konstruktor verfügen, der einen HttpClient
als Parameter akzeptiert. Darüber hinaus sollte der TClient
-Typ nicht separat mit dem DI-Container registriert werden, da dies dazu führt, dass die spätere Registrierung die frühere überschreibt.
IHttpClientFactory
kann in Verbindung mit Bibliotheken von Drittanbietern verwendet werden, z. B. Refit. Refit ist eine REST-Bibliothek für .NET. Sie ermöglicht deklarative REST-API-Definitionen, die Schnittstellenmethoden Endpunkten zuordnen. Eine Implementierung der Schnittstelle wird dynamisch von RestService
generiert. HttpClient
wird für die externen HTTP-Aufrufe verwendet.
Berücksichtigen Sie den folgenden record
-Typ:
namespace Shared;
public record class Todo(
int UserId,
int Id,
string Title,
bool Completed);
Das folgende Beispiel basiert auf dem Refit.HttpClientFactory
-NuGet-Paket und ist eine einfache Schnittstelle:
using Refit;
using Shared;
namespace GeneratedHttp.Example;
public interface ITodoService
{
[Get("/todos?userId={userId}")]
Task<Todo[]> GetUserTodosAsync(int userId);
}
Die vorangehende C#-Schnittstelle:
GetUserTodosAsync
, die eine Task<Todo[]>
-Instanz zurückgibt.Refit.GetAttribute
-Attribut mit dem Pfad und der Abfragezeichenfolge für die externe API.Ein typisierter Client kann hinzugefügt werden. Refit wird zum Generieren der Implementierung verwendet:
using GeneratedHttp.Example;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging;
using Refit;
using Shared;
HostApplicationBuilder builder = Host.CreateApplicationBuilder(args);
builder.Services.AddRefitClient<ITodoService>()
.ConfigureHttpClient(client =>
{
// Set the base address of the named client.
client.BaseAddress = new Uri("https://jsonplaceholder.typicode.com/");
// Add a user-agent default request header.
client.DefaultRequestHeaders.UserAgent.ParseAdd("dotnet-docs");
});
Die definierte Schnittstelle kann bei Bedarf mit der von DI und Refit bereitgestellten Implementierung verwendet werden.
In den vorangehenden Beispielen verwenden alle Anforderungen das GET
-HTTP-Verb. HttpClient
unterstützt ebenso andere HTTP-Verben, einschließlich der folgenden:
POST
PUT
DELETE
PATCH
Eine komplette Liste der unterstützten HTTP-Verben finden Sie unter HttpMethod. Weitere Informationen zum Senden von HTTP-Anforderungen finden Sie unter Senden einer Anforderung mit HttpClient.
Im folgenden Beispiel wird gezeigt, wie Sie eine HTTP-POST
-Anforderung vornehmen:
public async Task CreateItemAsync(Item item)
{
using StringContent json = new(
JsonSerializer.Serialize(item, new JsonSerializerOptions(JsonSerializerDefaults.Web)),
Encoding.UTF8,
MediaTypeNames.Application.Json);
using HttpResponseMessage httpResponse =
await httpClient.PostAsync("/api/items", json);
httpResponse.EnsureSuccessStatusCode();
}
Für die CreateItemAsync
-Methoden im Code oben gilt Folgendes:
Item
-Parameter mithilfe von System.Text.Json
in JSON. Dabei wird eine Instanz von JsonSerializerOptions verwenden, um den Serialisierungsprozess zu konfigurieren.HttpClient
unterstützt auch andere Inhaltstypen. Beispiel: MultipartContent und StreamContent. Eine komplette Liste der unterstützten Inhaltstypen finden Sie unter HttpContent.
Das folgende Beispiel zeigt eine HTTP-PUT
-Anforderung:
public async Task UpdateItemAsync(Item item)
{
using StringContent json = new(
JsonSerializer.Serialize(item, new JsonSerializerOptions(JsonSerializerDefaults.Web)),
Encoding.UTF8,
MediaTypeNames.Application.Json);
using HttpResponseMessage httpResponse =
await httpClient.PutAsync($"/api/items/{item.Id}", json);
httpResponse.EnsureSuccessStatusCode();
}
Der vorangehende Code ist dem POST
-Beispiel sehr ähnlich. Die UpdateItemAsync
-Methode ruft PutAsync anstelle von PostAsync
auf.
Das folgende Beispiel zeigt eine HTTP-DELETE
-Anforderung:
public async Task DeleteItemAsync(Guid id)
{
using HttpResponseMessage httpResponse =
await httpClient.DeleteAsync($"/api/items/{id}");
httpResponse.EnsureSuccessStatusCode();
}
Im vorangehenden Code ruft die DeleteItemAsync
-Methode DeleteAsync auf. Da HTTP-DELETE-Anforderungen normalerweise keinen Text enthalten, stellt die DeleteAsync
-Methode keine Überladung bereit, die eine Instanz von HttpContent
akzeptiert.
Weitere Informationen zur Verwendung unterschiedlicher HTTP-Verben mit HttpClient
finden Sie unter HttpClient.
Bei jedem Aufruf von CreateClient
in der IHttpClientFactory
wird eine neue Instanz von HttpClient
zurückgegeben. Pro Clientname wird eine HttpClientHandler-Instanz erstellt. Die Factory verwaltet die Lebensdauer der HttpClientHandler
-Instanzen.
IHttpClientFactory
nimmt die Zwischenspeicherung der HttpClientHandler
-Instanzen vor, die von der Factory zum Reduzieren des Ressourcenverbrauchs erstellt wurden. Eine HttpClientHandler
-Instanz kann aus dem Cache wiederverwendet werden, wenn eine neue HttpClient
-Instanz erstellt wird und deren Lebensdauer noch nicht abgelaufen ist.
Das Zwischenspeichern von Handlern ist ein wünschenswerter Vorgang, da jeder Handler in der Regel seinen zugrunde liegenden HTTP-Verbindungspool selbst verwaltet. Die Erstellung von mehr Handlern als nötig kann zu Socketerschöpfung und Verbindungsverzögerungen führen. Einige Handler halten Verbindungen auch unbegrenzt offen, was verhindert, dass der Handler auf DNS-Änderungen reagiert.
Die Standardlebensdauer von Handlern beträgt zwei Minuten. Um den Standardwert zu überschreiben, rufen Sie SetHandlerLifetime für jeden Client für die IServiceCollection
auf:
services.AddHttpClient("Named.Client")
.SetHandlerLifetime(TimeSpan.FromMinutes(5));
Wichtig
HttpClient
-Instanzen, die von IHttpClientFactory
erstellt werden, sollen kurzlebig sein.
Das Recyceln und erneute Erstellen von HttpMessageHandler
n nach Ablauf ihrer Lebensdauer ist für IHttpClientFactory
unerlässlich, um sicherzustellen, dass Handler auf DNS-Änderungen reagieren. HttpClient
ist bei der Erstellung an eine bestimmte Handlerinstanz gebunden, sodass neue HttpClient
-Instanzen rechtzeitig angefordert werden sollten, um sicherzustellen, dass der Client den aktualisierten Handler erhält.
Die Entsorgung solcher HttpClient
-Instanzen, die von der Factory erstellt wurden, führt nicht zu Socketerschöpfung, da ihre Entsorgung keine Entsorgung des HttpMessageHandler
auslöst. IHttpClientFactory
verfolgt Ressourcen nach und entsorgt diese, die zum Erstellen von HttpClient
-Instanzen verwendet werden, insbesondere die HttpMessageHandler
-Instanzen, sobald ihre Lebensdauer abläuft und sie nicht mehr von einem HttpClient
verwendet werden.
Eine einzelne HttpClient
-Instanz über einen langen Zeitraum am Leben zu halten, ist ein gängiges Muster, das als Alternative zu IHttpClientFactory
verwendet werden kann. Für dieses Muster ist jedoch zusätzliches Setup erforderlich, z. B. PooledConnectionLifetime
. Sie können entweder langlebige Clients mit PooledConnectionLifetime
oder kurzlebige Clients verwenden, die von IHttpClientFactory
erstellt werden. Informationen dazu, welche Strategie in Ihrer App verwendet werden sollte, finden Sie unter Richtlinien für die Verwendung von HTTP-Clients.
Es kann notwendig sein, die Konfiguration des inneren von einem Client verwendeten HttpMessageHandler zu steuern.
IHttpClientBuilder wird zurückgegeben, wenn benannte oder typisierte Clients hinzugefügt werden. Die Erweiterungsmethode ConfigurePrimaryHttpMessageHandler kann zum Definieren eines Delegaten für die IServiceCollection
verwendet werden. Der Delegat wird verwendet, um den primären HttpMessageHandler
zu erstellen und konfigurieren, der von dem Client verwendet wird:
.ConfigurePrimaryHttpMessageHandler(() =>
{
return new HttpClientHandler
{
AllowAutoRedirect = false,
UseDefaultCredentials = true
};
});
Wenn Sie die HttClientHandler
konfigurieren, können Sie einen Proxy für die HttpClient
-Instanz unter verschiedenen anderen Eigenschaften des Handlers angeben. Weitere Informationen finden Sie unter Proxy pro Client.
Es gibt mehrere zusätzliche Konfigurationsoptionen zum Steuern von IHttpClientHandler
:
Methode | Beschreibung |
---|---|
AddHttpMessageHandler | Fügt einen zusätzlichen Meldungshandler für einen benannten HttpClient hinzu. |
AddTypedClient | Konfiguriert die Bindung zwischen dem TClient und dem benannten HttpClient , der der IHttpClientBuilder -Methode zugeordnet ist. |
ConfigureHttpClient | Fügt einen Delegaten hinzu, der für die Konfiguration einer benannten HttpClient -Klasse verwendet wird. |
ConfigurePrimaryHttpMessageHandler | Konfiguriert die primäre HttpMessageHandler -Klasse aus dem Abhängigkeitsinjektionscontainer für eine benannte HttpClient -Klasse. |
RedactLoggedHeaders | Legt die Sammlung von HTTP-Headernamen fest, für die vor der Protokollierung Werte bearbeitet werden sollen. |
SetHandlerLifetime | Legt die Zeitspanne fest, für die eine HttpMessageHandler -Klasse wiederverwendet werden kann. Für jeden benannten Client kann ein eigener Wert für die Lebensdauer des Handlers konfiguriert werden. |
UseSocketsHttpHandler | Konfiguriert eine neue oder eine zuvor hinzugefügte SocketsHttpHandler -Instanz aus dem Container zum Einfügen von Abhängigkeiten, die als primärer Handler für einen benannten HttpClient -Handler verwendet werden soll. (nur .NET 5+) |
Die SocketsHttpHandler
-Implementierung von HttpMessageHandler
wurde in .NET Core 2.1 hinzugefügt, wodurch PooledConnectionLifetime
konfiguriert werden kann. Diese Einstellung wird verwendet, um sicherzustellen, dass der Handler auf DNS-Änderungen reagiert. Daher wird die Verwendung von SocketsHttpHandler
als Alternative zur Verwendung von IHttpClientFactory
betrachtet. Weitere Informationen finden Sie unter Richtlinien für die Verwendung von HTTP-Clients.
SocketsHttpHandler
Allerdings können und IHttpClientFactory
zusammen verwendet werden, um die Konfigurierbarkeit zu verbessern. Durch die Verwendung dieser beiden APIs profitieren Sie von der Konfigurierbarkeit sowohl auf niedriger Ebene (z. B. bei der Verwendung von LocalCertificateSelectionCallback
für die Auswahl dynamischer Zertifikate) als auch auf hoher Ebene (z. B. durch Nutzung von DI-Integration und mehrerer Clientkonfigurationen).
So verwenden Sie beide APIs:
SocketsHttpHandler
als PrimaryHandler
über ConfigurePrimaryHttpMessageHandler oder UseSocketsHttpHandler (nur .NET 5+).HandlerLifetime
angegeben war.SocketsHttpHandler
Verbindungspooling und Recycling verarbeitet, ist Handlerrecycling auf der IHttpClientFactory
-Ebene nicht mehr erforderlich. Sie können diese Einstellung deaktivieren, indem Sie HandlerLifetime
auf Timeout.InfiniteTimeSpan
festlegen.services.AddHttpClient(name)
.UseSocketsHttpHandler((handler, _) =>
handler.PooledConnectionLifetime = TimeSpan.FromMinutes(2)) // Recreate connection every 2 minutes
.SetHandlerLifetime(Timeout.InfiniteTimeSpan); // Disable rotation, as it is handled by PooledConnectionLifetime
Im obigen Beispiel wurden zufallsweise 2 Minuten zur Veranschaulichung ausgewählt und an einen standardmäßigen HandlerLifetime
-Wert ausgerichtet. Sie sollten den Wert basierend auf der erwarteten Häufigkeit von DNS- oder anderen Netzwerkänderungen auswählen. Weitere Informationen finden Sie im Abschnitt DNS-Verhalten in den HttpClient
Richtlinien und im Abschnitt „Hinweise“ in der PooledConnectionLifetime API-Dokumentation.
Bei Verwendung des Ansatzes mit benannten Clients wird IHttpClientFactory
in Dienste eingefügt, und HttpClient
-Instanzen werden erstellt, indem jedes Mal CreateClient aufgerufen wird, wenn ein HttpClient
benötigt wird.
Beim Ansatz mit typisierten Clients sind typisierte Clients jedoch vorübergehende Objekte, die normalerweise in Dienste eingefügt werden. Dies kann zu einem Problem führen, da ein typisierter Client in einen Singleton-Dienst eingefügt werden kann.
Wichtig
Von typisierten Clients wird erwartet, dass sie im gleichen Sinne kurzlebig sind wie HttpClient
-Instanzen, die von IHttpClientFactory
erstellt werden (weitere Informationen finden Sie unter HttpClient
-Lebensdauerverwaltung). Sobald eine typisierte Clientinstanz erstellt wird, besitzt IHttpClientFactory
keine Kontrolle über sie. Wenn eine typisierte Clientinstanz in einem Singleton erfasst wird, kann dies verhindern, dass auf DNS-Änderungen reagiert wird, was einen der Zwecke von IHttpClientFactory
vereitelt.
Wenn Sie HttpClient
-Instanzen in einem Singleton-Dienst verwenden müssen, sollten Sie die folgenden Optionen in Betracht ziehen:
IHttpClientFactory
in den Singleton-Dienst einfügen und bei Bedarf HttpClient
-Instanzen neu erstellen.SocketsHttpHandler
mit konfiguriertem PooledConnectionLifetime
-Wert als primären Handler. Weitere Informationen zur Verwendung von SocketsHttpHandler
mit IHttpClientFactory
finden Sie im Abschnitt Verwenden von IHttpClientFactory zusammen mit SocketsHttpHandler.IHttpClientFactory
erstellt für jede HttpMessageHandler
-Instanz einen separaten DI-Bereich. Diese DI-Bereiche sind von Anwendungs-DI-Bereichen getrennt (z. B. vom ASP.NET-Bereich für eingehende Anforderungen oder einem vom Benutzer erstellten manuellen DI-Bereich), sodass sie keine bereichsbezogenen Dienstinstanzen gemeinsam nutzen. Nachrichtenhandlerbereiche sind an die Lebensdauer des Handlers gebunden und können Anwendungsbereiche überdauern, was beispielsweise dazu führen kann, dass dieselbe HttpMessageHandler
-Instanz mit denselben eingefügten Bereichsabhängigkeiten zwischen mehreren eingehenden Anforderungen wiederverwendet wird.
Benutzern wird dringend empfohlen, bereichsbezogene Informationen (z. B. Daten von HttpContext
) nicht in HttpMessageHandler
-Instanzen zwischenzuspeichern und bereichsbezogene Abhängigkeiten mit Vorsicht zu verwenden, um zu vermeiden, dass vertrauliche Informationen veröffentlicht werden.
Wenn Sie von Ihrem Meldungshandler aus Zugriff auf einen App-DI-Bereich benötigen (beispielsweise zur Authentifizierung), kapseln Sie bereichsbezogene Logik in einem separaten vorübergehenden DelegatingHandler
, und umschließen ihn mit einer HttpMessageHandler
-Instanz aus dem IHttpClientFactory
-Cache. Um auf den Handler zuzugreifen, rufen Sie IHttpMessageHandlerFactory.CreateHandler für jeden registrierten benannten Client auf. In diesem Fall erstellen Sie eine HttpClient
-Instanz selbst mithilfe des erstellten Handlers.
Das folgende Beispiel zeigt das Erstellen eines HttpClient
mit einem bereichsbezogenen DelegatingHandler
:
if (scopeAwareHandlerType != null)
{
if (!typeof(DelegatingHandler).IsAssignableFrom(scopeAwareHandlerType))
{
throw new ArgumentException($"""
Scope aware HttpHandler {scopeAwareHandlerType.Name} should
be assignable to DelegatingHandler
""");
}
// Create top-most delegating handler with scoped dependencies
scopeAwareHandler = (DelegatingHandler)_scopeServiceProvider.GetRequiredService(scopeAwareHandlerType); // should be transient
if (scopeAwareHandler.InnerHandler != null)
{
throw new ArgumentException($"""
Inner handler of a delegating handler {scopeAwareHandlerType.Name} should be null.
Scope aware HttpHandler should be registered as Transient.
""");
}
}
// Get or create HttpMessageHandler from HttpClientFactory
HttpMessageHandler handler = _httpMessageHandlerFactory.CreateHandler(name);
if (scopeAwareHandler != null)
{
scopeAwareHandler.InnerHandler = handler;
handler = scopeAwareHandler;
}
HttpClient client = new(handler);
Eine weitere Problemumgehung kann mit einer Erweiterungsmethode für die Registrierung eines bereichsbezogenen DelegatingHandler
und einer IHttpClientFactory
-Standardregistrierung durch einen vorübergehenden Dienst mit Zugriff auf den aktuellen App-Bereich folgen:
public static IHttpClientBuilder AddScopeAwareHttpHandler<THandler>(
this IHttpClientBuilder builder) where THandler : DelegatingHandler
{
builder.Services.TryAddTransient<THandler>();
if (!builder.Services.Any(sd => sd.ImplementationType == typeof(ScopeAwareHttpClientFactory)))
{
// Override default IHttpClientFactory registration
builder.Services.AddTransient<IHttpClientFactory, ScopeAwareHttpClientFactory>();
}
builder.Services.Configure<ScopeAwareHttpClientFactoryOptions>(
builder.Name, options => options.HttpHandlerType = typeof(THandler));
return builder;
}
Weitere Informationen finden Sie im vollständigen Beispiel.
IHttpClientFactory
Feedback zu .NET
.NET ist ein Open Source-Projekt. Wählen Sie einen Link aus, um Feedback zu geben:
Ereignisse
17. März, 21 Uhr - 21. März, 10 Uhr
Nehmen Sie an der Meetup-Serie teil, um skalierbare KI-Lösungen basierend auf realen Anwendungsfällen mit Mitentwicklern und Experten zu erstellen.
Jetzt registrierenTraining
Modul
Implementieren von HTTP-Vorgängen in ASP.NET Core Blazor-Web-Apps - Training
Implementieren von HTTP-Vorgängen in ASP.NET Core Blazor-Web-Apps
Dokumentation
Verwenden von IHttpClientFactory zum Implementieren widerstandsfähiger HTTP-Anforderungen - .NET
Erfahren Sie, wie Sie IHttpClientFactory verwenden, die seit .NET Core 2.1 zum Erstellen von 'HttpClient'-Instanzen verfügbar sind, wodurch sie für Sie in Ihren Anwendungen einfach verwendet werden können.
HttpClient-Richtlinien für .NET - .NET
Erfahren Sie mehr über die Verwendung von HttpClient-Instanzen zum Senden von HTTP-Anforderungen und darüber, wie Sie Clients mithilfe von IHttpClientFactory in Ihren .NET-Apps verwalten können.
Behandeln von Problemen mit IHttpClientFactory - .NET
Erfahren Sie, wie Sie allgemeine HttpClient- und IHttpClientFactory-Probleme beheben.
Stellen von HTTP-Anforderungen mithilfe von IHttpClientFactory in ASP.NET Core
Erfahren Sie mehr über die Verwendung der IHttpClientFactory-Schnittstelle, um logische HttpClient-Instanzen in ASP.NET Core zu verwalten.