IHttpClientFactory z platformą .NET
W tym artykule dowiesz się, jak używać interfejsu IHttpClientFactory
do tworzenia HttpClient
typów z różnymi podstawami platformy .NET, takimi jak wstrzykiwanie zależności (DI), rejestrowanie i konfiguracja. Typ HttpClient został wprowadzony w programie .NET Framework 4.5, który został wydany w 2012 roku. Innymi słowy, to było od jakiegoś czasu. HttpClient
służy do tworzenia żądań HTTP i obsługi odpowiedzi HTTP z zasobów internetowych zidentyfikowanych przez Urielement . Protokół HTTP stanowi zdecydowaną większość całego ruchu internetowego.
Dzięki nowoczesnym zasadom tworzenia aplikacji, które napędzają najlepsze rozwiązania, usługa służy jako abstrakcja fabryki, IHttpClientFactory która może tworzyć HttpClient
wystąpienia z konfiguracjami niestandardowymi. IHttpClientFactory wprowadzono w programie .NET Core 2.1. Typowe obciążenia platformy .NET oparte na protokole HTTP mogą z łatwością korzystać z odpornego i przejściowego oprogramowania pośredniczącego innych firm.
Uwaga
Jeśli aplikacja wymaga plików cookie, lepszym rozwiązaniem może być unikanie korzystania z IHttpClientFactory aplikacji. Aby uzyskać alternatywne sposoby zarządzania klientami, zobacz Wytyczne dotyczące korzystania z klientów HTTP.
Ważne
Zarządzanie okresem istnienia wystąpień utworzonych HttpClient
przez IHttpClientFactory
program jest zupełnie inne niż wystąpienia utworzone ręcznie. Strategie to użycie krótkoterminowych klientów utworzonych przez IHttpClientFactory
klientów lub klientów długotrwałych z konfiguracjąPooledConnectionLifetime
. Aby uzyskać więcej informacji, zobacz sekcję Zarządzanie okresem istnienia klienta HttpClient i wskazówki dotyczące korzystania z klientów HTTP.
Typ IHttpClientFactory
Cały przykładowy kod źródłowy podany w tym artykule wymaga zainstalowania Microsoft.Extensions.Http
pakietu NuGet. Ponadto przykłady kodu pokazują użycie żądań HTTP GET
w celu pobrania obiektów użytkownika Todo
z bezpłatnego interfejsu API symbolu zastępczego {JSON}.
Podczas wywoływania dowolnej metody AddHttpClient rozszerzenia dodajesz IHttpClientFactory
usługi i powiązane z nimi usługi do elementu IServiceCollection. Typ IHttpClientFactory
oferuje następujące korzyści:
- Uwidacznia klasę
HttpClient
jako typ gotowy do di. - Zapewnia centralną lokalizację nazewnictwa i konfigurowania wystąpień logicznych
HttpClient
. - Koduje koncepcję wychodzącego oprogramowania pośredniczącego za pośrednictwem delegowania programów obsługi w programie
HttpClient
. - Udostępnia metody rozszerzeń oprogramowania pośredniczącego opartego na usłudze Polly, aby korzystać z delegowania programów obsługi w programie
HttpClient
. - Zarządza buforowaniem i okresem istnienia wystąpień bazowych HttpClientHandler . Automatyczne zarządzanie pozwala uniknąć typowych problemów z systemem nazw domen (DNS), które występują podczas ręcznego zarządzania
HttpClient
okresami istnienia. - Dodaje konfigurowalne środowisko rejestrowania (za pośrednictwem ILogger) dla wszystkich żądań wysyłanych za pośrednictwem klientów utworzonych przez fabrykę.
Konsumpcji
W aplikacji można użyć kilku sposobów IHttpClientFactory
:
Najlepsze podejście zależy od wymagań aplikacji.
Podstawowy sposób użycia
Aby zarejestrować obiekt , wywołaj metodę IHttpClientFactory
AddHttpClient
:
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();
Korzystanie z usług może wymagać parametru IHttpClientFactory
jako konstruktora z di. Poniższy kod używa IHttpClientFactory
metody do utworzenia HttpClient
wystąpienia:
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 [];
}
}
Użycie IHttpClientFactory
metody podobnej w poprzednim przykładzie jest dobrym sposobem refaktoryzacji istniejącej aplikacji. Nie ma to wpływu na sposób HttpClient
użycia. W miejscach, w których HttpClient
wystąpienia są tworzone w istniejącej aplikacji, zastąp te wystąpienia wywołaniami metody CreateClient.
Nazwani klienci
Nazwani klienci są dobrym wyborem w następujących przypadkach:
- Aplikacja wymaga wielu różnych zastosowań programu
HttpClient
. - Wiele
HttpClient
wystąpień ma różne konfiguracje.
Konfigurację nazwy HttpClient
można określić podczas rejestracji w pliku IServiceCollection
:
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");
});
W poprzednim kodzie klient jest skonfigurowany przy użyciu następujących elementów:
- Nazwa pobrana z konfiguracji w obszarze
"TodoHttpClientName"
. - Adres
https://jsonplaceholder.typicode.com/
podstawowy . "User-Agent"
Nagłówek.
Konfigurację można użyć do określenia nazw klientów HTTP, co jest pomocne w celu uniknięcia błędu klientów podczas dodawania i tworzenia. W tym przykładzie plik appsettings.json służy do konfigurowania nazwy klienta HTTP:
{
"TodoHttpClientName": "JsonPlaceholderApi"
}
Można łatwo rozszerzyć tę konfigurację i zapisać więcej szczegółów na temat sposobu działania klienta HTTP. Aby uzyskać więcej informacji, zobacz Konfiguracja na platformie .NET.
Tworzenie klienta
Za każdym razem CreateClient jest wywoływana:
- Zostanie utworzone nowe wystąpienie programu
HttpClient
. - Akcja konfiguracji jest wywoływana.
Aby utworzyć nazwanego klienta, przekaż jego nazwę do 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 [];
}
}
W poprzednim kodzie żądanie HTTP nie musi określać nazwy hosta. Kod może przekazać tylko ścieżkę, ponieważ używany jest adres podstawowy skonfigurowany dla klienta.
Wpisanych klientów
Typizowane klienci:
- Zapewnij te same możliwości co nazwani klienci bez konieczności używania ciągów jako kluczy.
- Zapewnianie funkcji IntelliSense i kompilatora pomocy podczas korzystania z klientów.
- Podaj pojedynczą lokalizację do skonfigurowania i interakcji z określonym
HttpClient
elementem . Na przykład można użyć jednego typu klienta:- W przypadku pojedynczego punktu końcowego zaplecza.
- Aby hermetyzować całą logikę do obsługi punktu końcowego.
- Praca z di i może być wstrzykiwana tam, gdzie jest to wymagane w aplikacji.
Typowany klient akceptuje HttpClient
parametr w konstruktorze:
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();
}
Powyższy kod:
- Konfiguracja jest ustawiana po dodaniu wpisanego klienta do kolekcji usług.
- Element
HttpClient
jest przypisywany jako zmienna o zakresie klasy (pole) i używany z uwidocznionych interfejsów API.
Metody specyficzne dla interfejsu API można utworzyć, aby uwidaczniać HttpClient
funkcje. Na przykład GetUserTodosAsync
metoda hermetyzuje kod w celu pobrania obiektów specyficznych dla Todo
użytkownika.
Następujące wywołania AddHttpClient kodu w celu zarejestrowania wpisanej klasy klienta:
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");
});
Typowany klient jest zarejestrowany jako przejściowy z di. W poprzednim kodzie AddHttpClient
rejestruje się TodoService
jako usługa przejściowa. Ta rejestracja używa metody fabryki do:
- Utwórz wystąpienie elementu
HttpClient
. - Utwórz wystąpienie klasy , przekazując wystąpienie
TodoService
do jego konstruktoraHttpClient
.
Ważne
Korzystanie z typowanych klientów w usługach jednotonowych może być niebezpieczne. Aby uzyskać więcej informacji, zobacz sekcję Unikanie typiowanych klientów w usługach jednotonowych .
Uwaga
Podczas rejestrowania typizowanego klienta za AddHttpClient<TClient>
pomocą metody TClient
typ musi mieć konstruktor, który akceptuje HttpClient
jako parametr. TClient
Ponadto typ nie powinien być zarejestrowany w kontenerze di oddzielnie, ponieważ spowoduje to późniejsze zastąpienie poprzedniej rejestracji.
Wygenerowani klienci
IHttpClientFactory
można używać w połączeniu z bibliotekami innych firm, takimi jak Refit. Refit to biblioteka REST dla platformy .NET. Umożliwia ona deklaratywne definicje interfejsu API REST, mapowanie metod interfejsu na punkty końcowe. Implementacja interfejsu jest generowana dynamicznie przez RestService
element , za pomocą polecenia HttpClient
w celu wykonywania zewnętrznych wywołań HTTP.
Rozważ następujący record
typ:
namespace Shared;
public record class Todo(
int UserId,
int Id,
string Title,
bool Completed);
Poniższy przykład opiera się na pakiecie Refit.HttpClientFactory
NuGet i jest prostym interfejsem:
using Refit;
using Shared;
namespace GeneratedHttp.Example;
public interface ITodoService
{
[Get("/todos?userId={userId}")]
Task<Todo[]> GetUserTodosAsync(int userId);
}
Poprzedni interfejs języka C#:
- Definiuje metodę o nazwie
GetUserTodosAsync
zwracającąTask<Todo[]>
wystąpienie. Refit.GetAttribute
Deklaruje atrybut ze ścieżką i ciągiem zapytania do zewnętrznego interfejsu API.
Można dodać typizowanego klienta, używając polecenia Refit w celu wygenerowania implementacji:
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");
});
Zdefiniowany interfejs można używać w razie potrzeby z implementacją dostarczaną przez di i refit.
Żądania POST, PUT i DELETE
W poprzednich przykładach wszystkie żądania HTTP używają czasownika GET
HTTP. HttpClient
Obsługuje również inne czasowniki HTTP, w tym:
POST
PUT
DELETE
PATCH
Aby uzyskać pełną listę obsługiwanych czasowników HTTP, zobacz HttpMethod. Aby uzyskać więcej informacji na temat wysyłania żądań HTTP, zobacz Wysyłanie żądania przy użyciu klienta HttpClient.
W poniższym przykładzie pokazano, jak wysłać żądanie HTTP POST
:
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();
}
W poprzednim kodzie CreateItemAsync
metoda:
- Serializuje
Item
parametr w formacie JSON przy użyciu poleceniaSystem.Text.Json
. Używa to wystąpienia JsonSerializerOptions klasy , aby skonfigurować proces serializacji. - Tworzy wystąpienie elementu StringContent w celu spakowania serializowanego kodu JSON do wysyłania w treści żądania HTTP.
- Wywołuje metodę PostAsync wysyłania zawartości JSON do określonego adresu URL. Jest to względny adres URL, który jest dodawany do obiektu HttpClient.BaseAddress.
- Wywołania EnsureSuccessStatusCode w celu zgłoszenia wyjątku, jeśli kod stanu odpowiedzi nie wskazuje powodzenia.
HttpClient
obsługuje również inne typy zawartości. Przykład: MultipartContent i StreamContent. Aby uzyskać pełną listę obsługiwanych zawartości, zobacz HttpContent.
W poniższym przykładzie przedstawiono żądanie HTTP PUT
:
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();
}
Powyższy kod jest bardzo podobny do przykładu POST
. Metoda UpdateItemAsync
wywołuje PutAsync metodę PostAsync
zamiast .
W poniższym przykładzie przedstawiono żądanie HTTP DELETE
:
public async Task DeleteItemAsync(Guid id)
{
using HttpResponseMessage httpResponse =
await httpClient.DeleteAsync($"/api/items/{id}");
httpResponse.EnsureSuccessStatusCode();
}
W poprzednim kodzie metoda wywołuje metodę DeleteItemAsync
DeleteAsync. Ponieważ żądania HTTP DELETE zwykle nie zawierają treści, DeleteAsync
metoda nie udostępnia przeciążenia, które akceptuje wystąpienie HttpContent
klasy .
Aby dowiedzieć się więcej na temat używania różnych czasowników HTTP w programie HttpClient
, zobacz HttpClient.
HttpClient
zarządzanie okresem istnienia
Nowe HttpClient
wystąpienie jest zwracane za każdym razem, gdy CreateClient
jest wywoływane w obiekcie IHttpClientFactory
. Jedno HttpClientHandler wystąpienie jest tworzone na nazwę klienta. Fabryka zarządza okresami HttpClientHandler
istnienia wystąpień.
IHttpClientFactory
Buforuje HttpClientHandler
wystąpienia utworzone przez fabrykę w celu zmniejszenia zużycia zasobów. Wystąpienie HttpClientHandler
może być ponownie używane z pamięci podręcznej podczas tworzenia nowego HttpClient
wystąpienia, jeśli jego okres istnienia nie wygasł.
Buforowanie programów obsługi jest pożądane, ponieważ każda procedura obsługi zwykle zarządza własną bazową pulą połączeń HTTP. Tworzenie większej liczby procedur obsługi niż jest to konieczne może spowodować wyczerpanie gniazd i opóźnienia połączeń. Niektóre programy obsługi utrzymują również połączenia otwarte na czas nieokreślony, co może uniemożliwić programowi obsługi reagowanie na zmiany DNS.
Domyślny okres istnienia programu obsługi to dwie minuty. Aby zastąpić wartość domyślną, wywołaj SetHandlerLifetime dla każdego klienta w pliku IServiceCollection
:
services.AddHttpClient("Named.Client")
.SetHandlerLifetime(TimeSpan.FromMinutes(5));
Ważne
HttpClient
wystąpienia utworzone przez IHttpClientFactory
program mają być krótkotrwałe.
Odtwarzanie i ponowne tworzenie
HttpMessageHandler
elementów po wygaśnięciu ich okresu istnienia jest niezbędne,IHttpClientFactory
aby zapewnić, że programy obsługi reagują na zmiany DNS.HttpClient
program jest powiązany z określonym wystąpieniem programu obsługi podczas jego tworzenia, dlatego należy zażądać nowychHttpClient
wystąpień w odpowiednim czasie, aby upewnić się, że klient uzyska zaktualizowaną procedurę obsługi.Usunięcie takich
HttpClient
wystąpień utworzonych przez fabrykę nie doprowadzi do wyczerpania gniazd, ponieważ jego usuwanie nie spowoduje usunięcia obiektuHttpMessageHandler
.IHttpClientFactory
śledzi i usuwa zasoby używane do tworzeniaHttpClient
wystąpień, w szczególnościHttpMessageHandler
wystąpień, gdy tylko ich okres istnienia wygaśnie i nieHttpClient
będzie już ich używać.
Utrzymywanie pojedynczego HttpClient
wystąpienia przy życiu przez długi czas jest typowym wzorcem, który może być używany jako alternatywa IHttpClientFactory
dla programu , jednak ten wzorzec wymaga dodatkowej konfiguracji, takiej jak .PooledConnectionLifetime
Można użyć klientów długotrwałych z PooledConnectionLifetime
klientami utworzonymi przez program lub krótkotrwałymi klientami utworzonymi przez IHttpClientFactory
program . Aby uzyskać informacje na temat strategii używanej w aplikacji, zobacz Wytyczne dotyczące korzystania z klientów HTTP.
Konfigurowanie HttpMessageHandler
Może być konieczne kontrolowanie konfiguracji wewnętrznej HttpMessageHandler używanej przez klienta.
Element IHttpClientBuilder jest zwracany podczas dodawania nazwanych lub wpisanych klientów. Metodę ConfigurePrimaryHttpMessageHandler rozszerzenia można użyć do zdefiniowania delegata w obiekcie IServiceCollection
. Delegat służy do tworzenia i konfigurowania podstawowego HttpMessageHandler
używanego przez tego klienta:
.ConfigurePrimaryHttpMessageHandler(() =>
{
return new HttpClientHandler
{
AllowAutoRedirect = false,
UseDefaultCredentials = true
};
});
Skonfigurowanie programu HttClientHandler
umożliwia określenie serwera proxy dla HttpClient
wystąpienia między różnymi innymi właściwościami programu obsługi. Aby uzyskać więcej informacji, zobacz Serwer proxy na klienta.
Dodatkowa konfiguracja
Istnieje kilka dodatkowych opcji konfiguracji do kontrolowania elementu IHttpClientHandler
:
Metoda | opis |
---|---|
AddHttpMessageHandler | Dodaje dodatkową procedurę obsługi komunikatów dla nazwanego HttpClient elementu . |
AddTypedClient | Konfiguruje powiązanie między elementem TClient i nazwanym HttpClient skojarzonym z elementem IHttpClientBuilder . |
ConfigureHttpClient | Dodaje delegata, który będzie używany do konfigurowania nazwanego HttpClient elementu . |
ConfigurePrimaryHttpMessageHandler | Konfiguruje element podstawowy HttpMessageHandler z kontenera wstrzykiwania zależności dla elementu o nazwie HttpClient . |
RedactLoggedHeaders | Ustawia kolekcję nazw nagłówków HTTP, dla których wartości powinny zostać zredagowane przed zalogowaniem. |
SetHandlerLifetime | Określa czas ponownego HttpMessageHandler użycia wystąpienia. Każdy nazwany klient może mieć własną skonfigurowaną wartość okresu istnienia programu obsługi. |
UseSocketsHttpHandler | Konfiguruje nowe lub wcześniej dodane SocketsHttpHandler wystąpienie z kontenera wstrzykiwania zależności do użycia jako podstawowy program obsługi dla nazwanego HttpClient elementu . (tylko platforma.NET 5 lub nowsza) |
Używanie elementu IHttpClientFactory razem z aplikacją SocketsHttpHandler
Implementacja SocketsHttpHandler
HttpMessageHandler
programu została dodana w programie .NET Core 2.1, co umożliwia PooledConnectionLifetime
skonfigurowanie. To ustawienie służy do zapewnienia, że program obsługi reaguje na zmiany DNS, więc użycie SocketsHttpHandler
jest uważane za alternatywę dla używania programu IHttpClientFactory
. Aby uzyskać więcej informacji, zobacz Wytyczne dotyczące korzystania z klientów HTTP.
SocketsHttpHandler
IHttpClientFactory
Można jednak używać ich razem w celu zwiększenia możliwości konfiguracji. Korzystając z obu tych interfejsów API, można korzystać z możliwości konfigurowania zarówno na niskim poziomie (na przykład w przypadku LocalCertificateSelectionCallback
wyboru certyfikatu dynamicznego), jak i wysokiego poziomu (na przykład przy użyciu integracji di i kilku konfiguracji klientów).
Aby użyć obu interfejsów API:
- Określ
SocketsHttpHandler
jakoPrimaryHandler
za pośrednictwem , ConfigurePrimaryHttpMessageHandlerlub UseSocketsHttpHandler (tylko .NET 5+). - Skonfiguruj na SocketsHttpHandler.PooledConnectionLifetime podstawie interwału, który ma zostać zaktualizowany przez system DNS, na przykład na wartość, która była wcześniej w
HandlerLifetime
pliku . - (Opcjonalnie) Ponieważ
SocketsHttpHandler
będzie obsługiwać buforowanie połączeń i recykling, przetwarzanieIHttpClientFactory
obsługi na poziomie nie jest już potrzebne. Można ją wyłączyć, ustawiając wartośćHandlerLifetime
Timeout.InfiniteTimeSpan
.
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
W powyższym przykładzie do celów ilustracyjnych wybrano dowolnie 2 minuty, wyrównując do wartości domyślnej HandlerLifetime
. Należy wybrać wartość na podstawie oczekiwanej częstotliwości zmian w systemie DNS lub innych zmianach sieci. Aby uzyskać więcej informacji, zobacz sekcję Zachowanie DNS w HttpClient
wytycznych i sekcję Uwagi w dokumentacji interfejsu PooledConnectionLifetime API.
Unikaj wpisywanych klientów w usługach jednotonowych
W przypadku korzystania z nazwanego podejścia IHttpClientFactory
klienta jest wstrzykiwany do usług, a HttpClient
wystąpienia są tworzone przez wywołanie CreateClient za każdym razem, gdy HttpClient
jest potrzebny.
Jednak w przypadku podejścia typizowanego klienta typizowane klienci są obiektami przejściowymi zwykle wstrzykiwanymi do usług. Może to spowodować problem, ponieważ typizowanego klienta można wstrzyknąć do pojedynczej usługi.
Ważne
Oczekuje się, że typowi klienci będą krótkotrwałi w tym samym sensie co HttpClient
wystąpienia utworzone przez IHttpClientFactory
(aby uzyskać więcej informacji, zobacz HttpClient
zarządzanie okresem istnienia). Po utworzeniu IHttpClientFactory
wpisanego wystąpienia klienta nie ma kontroli nad nim. Jeśli typizowane wystąpienie klienta jest przechwytywane w jednym miejscu, może to uniemożliwić reagowanie na zmiany DNS, pokonując jeden z celów IHttpClientFactory
programu .
Jeśli musisz używać HttpClient
wystąpień w pojedynczej usłudze, rozważ następujące opcje:
- Zamiast tego należy użyć nazwanego podejścia klienta , iniekcji
IHttpClientFactory
w pojedynczej usłudze i ponownego utworzeniaHttpClient
wystąpień w razie potrzeby. - Jeśli wymagane jest podejście typizowanego klienta , użyj polecenia
SocketsHttpHandler
z konfiguracjąPooledConnectionLifetime
jako podstawową procedurą obsługi. Aby uzyskać więcej informacji na temat używania z programemSocketsHttpHandler
IHttpClientFactory
, zobacz sekcję Using IHttpClientFactory razem z socketsHttpHandler.
Zakresy obsługi komunikatów w IHttpClientFactory
IHttpClientFactory
Tworzy oddzielny zakres di dla każdego HttpMessageHandler
wystąpienia. Te zakresy di są oddzielone od zakresów di aplikacji (na przykład ASP.NET zakresu żądań przychodzących lub zakresu ręcznego di utworzonego przez użytkownika), więc nie będą współużytkowane wystąpienia usługi o określonym zakresie. Zakresy obsługi komunikatów są powiązane z okresem istnienia programu obsługi i mogą przetrwać zakresy aplikacji, co może prowadzić na przykład do ponownego zastosowania tego samego wystąpienia z tymi samymi HttpMessageHandler
zależnościami o określonym zakresie między kilkoma żądaniami przychodzącymi.
Użytkownicy zdecydowanie zaleca się, aby nie buforować informacji związanych z zakresem (takich jak dane z HttpContext
) wewnątrz HttpMessageHandler
wystąpień i używać zależności o określonym zakresie z ostrożnością, aby uniknąć wycieku poufnych informacji.
Jeśli potrzebujesz dostępu do zakresu di aplikacji z programu obsługi komunikatów, na potrzeby uwierzytelniania na przykład należy hermetyzować logikę rozpoznawania zakresu w osobnym przejściowym DelegatingHandler
elememencie i opakowować je wokół HttpMessageHandler
wystąpienia z pamięci podręcznej IHttpClientFactory
. Aby uzyskać dostęp do wywołania IHttpMessageHandlerFactory.CreateHandler programu obsługi dla dowolnego zarejestrowanego nazwanego klienta. W takim przypadku samodzielnie utworzysz HttpClient
wystąpienie przy użyciu skonstruowanej procedury obsługi.
W poniższym przykładzie pokazano tworzenie obiektu HttpClient
z rozpoznawaniem DelegatingHandler
zakresu:
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);
Kolejnym obejściem może być metoda rozszerzenia służąca do rejestrowania zakresu DelegatingHandler
i zastępowania domyślnej IHttpClientFactory
rejestracji przez usługę przejściową z dostępem do bieżącego zakresu aplikacji:
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;
}
Aby uzyskać więcej informacji, zobacz pełny przykład.
Zobacz też
- Typowe
IHttpClientFactory
problemy z użyciem - Wstrzykiwanie zależności na platformie .NET
- Rejestrowanie na platformie .NET
- Konfiguracja na platformie .NET
- IHttpClientFactory
- IHttpMessageHandlerFactory
- HttpClient
- Wysyłaj żądania HTTP za pomocą klienta HttpClient
- Implementowanie ponawiania próby HTTP przy użyciu wycofywania wykładniczego