Použití IHttpClientFactory k implementaci odolných požadavků HTTP
IHttpClientFactory je kontraktem, který implementuje nástroj DefaultHttpClientFactory dogmatickým Factory, který je k dispozici od .NET Core 2,1 pro vytváření HttpClient instancí, které se mají použít ve vašich aplikacích.
Problémy s původní třídou HttpClient dostupnou v .NET
Původní a dobře známou HttpClient třídu lze snadno použít, ale v některých případech ji nepoužívá mnoho vývojářů.
I když tato třída implementuje IDisposable , deklaraci a vytvoření instance v rámci using příkazu není preferována, protože když dojde k HttpClient uvolnění objektu, základní soket není okamžitě uvolněn, což může vést k problému s vyčerpáním soketu . Další informace o tomto problému najdete v blogovém příspěvku, který používáte HttpClient, a který je destabilizující vašemu softwaru.
Proto HttpClient má být vytvořena instance jednou a znovu použita po celou dobu životnosti aplikace. Vytvoření instance HttpClient třídy pro každý požadavek vyčerpá počet soketů, které jsou k dispozici v případě velkého zatížení. K tomuto problému dojde v důsledku SocketException chyb. Možné přístupy k vyřešení tohoto problému jsou založené na vytvoření HttpClient objektu jako singleton nebo static, jak je vysvětleno v tomto článku o použití HttpClient. Může to být dobré řešení pro krátkodobé konzolové aplikace nebo podobné, které běží několikrát denně.
Dalším problémem, ve kterém se vývojáři spouštějí, je použití sdílené instance HttpClient v dlouhotrvajících procesech. v situaci, kdy je instance HttpClient vytvořena jako typ singleton nebo statický objekt, nedokáže zpracovat změny DNS, jak je popsáno v tomto problému v úložišti dotnet/runtime GitHub.
Problém ale není v zásadě za se HttpClient , ale s výchozím konstruktorem pro HttpClient, protože vytvoří novou konkrétní instanci HttpMessageHandler , která je v tom, který má vyčerpání soketů a DNS změny výše uvedené.
Rozhraní HttpClient .NET Core 2,1 představilo IHttpClientFactory rozhraní, které se dá použít ke konfiguraci a vytváření HttpClient instancí v aplikaci prostřednictvím injektáže závislostí (di), aby vyřešilo výše uvedené problémy a aby bylo možné spravovat instance. Poskytuje také rozšíření pro middleware založené na Polly, která umožňují využít výhod delegování obslužných rutin v HttpClient.
Polly je dočasná knihovna pro zpracování chyb, která vývojářům pomáhá zajistit odolnost proti svým aplikacím pomocí některých předdefinovaných zásad, které jsou bezpečné pro práci v Fluent a vlákně.
Výhody použití IHttpClientFactory
Aktuální implementace IHttpClientFactory , která také implementuje IHttpMessageHandlerFactory , nabízí následující výhody:
- Poskytuje centrální umístění pro pojmenovávání a konfiguraci logických
HttpClientobjektů. Můžete například nakonfigurovat klienta (agenta služeb), který je předem nakonfigurovaný pro přístup k určité mikroslužbě. - Codify koncept odchozího middleware prostřednictvím delegování obslužných rutin v
HttpClienta implementace middleware založeného na Polly, který využívá zásady Polly pro zajištění odolnosti. HttpClientjiž má koncepci delegování obslužných rutin, které by mohly být propojeny pro odchozí požadavky HTTP. Můžete zaregistrovat klienty HTTP do továrny a pomocí obslužné rutiny Polly použít zásady Polly pro opakování, CircuitBreakers a tak dále.- Spravujte dobu života, HttpMessageHandler abyste se vyhnuli uvedeným problémům nebo problémům, ke kterým může dojít při správě
HttpClientživotního cyklu.
Tip
HttpClientInstance vložené pomocí di mohou být odstraněny bezpečně, protože přidružený HttpMessageHandler je spravováno objektem pro vytváření. Vzhledem k tomu, že vložené HttpClient instance jsou vymezené z di perspektivy.
Poznámka
implementace IHttpClientFactory ( DefaultHttpClientFactory ) je úzce svázána s implementací DI v Microsoft.Extensions.DependencyInjection balíčku NuGet. další informace o použití jiných kontejnerů DI naleznete v této GitHub diskuzi.
Několik způsobů použití IHttpClientFactory
V aplikaci můžete použít několik způsobů IHttpClientFactory :
- Základní použití
- Použití pojmenovaných klientů
- Použití typových klientů
- Použít vygenerované klienty
Pro účely zkrácení vám tento návod ukáže, jak se používá IHttpClientFactory , aby bylo možné použít typové klienty (model agenta služby). Všechny možnosti jsou však zdokumentovány a jsou aktuálně uvedeny v tomto článku, který se týká IHttpClientFactory využití.
Jak používat typové klienty s IHttpClientFactory
Co je to "Typový klient"? Je to jenom ta HttpClient , která je předem nakonfigurovaná pro konkrétní použití. Tato konfigurace může zahrnovat konkrétní hodnoty, jako je základní server, hlavičky protokolu HTTP nebo časové limity.
Následující diagram znázorňuje, jak se používají typové klienty s IHttpClientFactory :

Obrázek 8-4. Použití IHttpClientFactory s typovými třídami klienta.
Na výše uvedeném obrázku, a ClientService (používá ho řadič nebo kód klienta), používá HttpClient vytvořenou registrovanou IHttpClientFactory . Tento objekt pro vytváření přiřadí HttpMessageHandler z fondu do HttpClient . HttpClientLze nakonfigurovat zásady Polly při registraci IHttpClientFactory v kontejneru di s metodou rozšíření AddHttpClient .
pokud chcete nakonfigurovat výše uvedenou strukturu, přidejte IHttpClientFactory ji do své aplikace nainstalováním Microsoft.Extensions.Http balíčku NuGet, který obsahuje AddHttpClient metodu rozšíření pro IServiceCollection . Tato metoda rozšíření registruje interní DefaultHttpClientFactory třídu, která se má použít jako typ singleton pro rozhraní IHttpClientFactory . Definuje přechodnou konfiguraci pro HttpMessageHandlerBuilder . Tato obslužná rutina zprávy ( HttpMessageHandler objekt), která je pořízena z fondu, je používána HttpClient vrácenou z továrny.
V dalším kódu vidíte, jak AddHttpClient() se dá použít k registraci typových klientů (agentů služeb), které je potřeba použít HttpClient .
// Startup.cs
//Add http client services at ConfigureServices(IServiceCollection services)
services.AddHttpClient<ICatalogService, CatalogService>();
services.AddHttpClient<IBasketService, BasketService>();
services.AddHttpClient<IOrderingService, OrderingService>();
Registrace služeb klienta, jak je znázorněno v předchozím kódu, vytvoří DefaultClientFactory HttpClient pro každou službu Standard.
Můžete také přidat konfiguraci specifickou pro instanci v registraci, například nakonfigurovat základní adresu a přidat některé zásady odolnosti, jak je znázorněno v následujícím kódu:
services.AddHttpClient<ICatalogService, CatalogService>(client =>
{
client.BaseAddress = new Uri(Configuration["BaseUrl"]);
})
.AddPolicyHandler(GetRetryPolicy())
.AddPolicyHandler(GetCircuitBreakerPolicy());
Podobně jako v tomto příkladu vidíte jednu z výše uvedených zásad v následujícím kódu:
static IAsyncPolicy<HttpResponseMessage> GetRetryPolicy()
{
return HttpPolicyExtensions
.HandleTransientHttpError()
.OrResult(msg => msg.StatusCode == System.Net.HttpStatusCode.NotFound)
.WaitAndRetryAsync(6, retryAttempt => TimeSpan.FromSeconds(Math.Pow(2, retryAttempt)));
}
Další podrobnosti o používání Polly najdete v dalším článku.
HttpClient doby života
Pokaždé, když získáte HttpClient objekt z IHttpClientFactory , je vrácena nová instance. Každá z nich ale HttpClient používá HttpMessageHandler fond a znovu IHttpClientFactory ho používá ke snížení spotřeby prostředků, pokud HttpMessageHandler Doba života ještě nevypršela.
Sdružování obslužných rutin je žádoucí, protože každá obslužná rutina obvykle spravuje vlastní podkladová připojení HTTP; vytváření dalších obslužných rutin, než je potřeba, může způsobit zpoždění připojení. Některé obslužné rutiny také udržují připojení otevřené po neomezenou dobu, což může zabránit obslužné rutině v rekomunikaci se změnami DNS.
HttpMessageHandlerObjekty ve fondu mají dobu života, která je doba, po kterou HttpMessageHandler lze instanci ve fondu znovu použít. Výchozí hodnota je dvě minuty, ale je možné ji přepsat na typového klienta. Chcete-li ho přepsat, zavolejte SetHandlerLifetime() na IHttpClientBuilder to, které je vráceno při vytváření klienta, jak je znázorněno v následujícím kódu:
//Set 5 min as the lifetime for the HttpMessageHandler objects in the pool used for the Catalog Typed Client
services.AddHttpClient<ICatalogService, CatalogService>()
.SetHandlerLifetime(TimeSpan.FromMinutes(5));
Každý typový klient může mít svou vlastní nakonfigurovanou hodnotu životnosti obslužných rutin. Nastavte dobu života na InfiniteTimeSpan Zakázat vypršení platnosti obslužné rutiny.
Implementujte typové klientské třídy, které používají vložené a nakonfigurované HttpClient
Jako předchozí krok musíte mít definované vaše typové klientské třídy, například třídy v ukázkovém kódu, jako je například "BasketService", "CatalogService", "OrderingService" atd. – typový klient je třída, která přijímá HttpClient objekt (vložený prostřednictvím jeho konstruktoru) a používá ho k volání některé vzdálené služby HTTP. Například:
public class CatalogService : ICatalogService
{
private readonly HttpClient _httpClient;
private readonly string _remoteServiceBaseUrl;
public CatalogService(HttpClient httpClient)
{
_httpClient = httpClient;
}
public async Task<Catalog> GetCatalogItems(int page, int take,
int? brand, int? type)
{
var uri = API.Catalog.GetAllCatalogItems(_remoteServiceBaseUrl,
page, take, brand, type);
var responseString = await _httpClient.GetStringAsync(uri);
var catalog = JsonConvert.DeserializeObject<Catalog>(responseString);
return catalog;
}
}
Typový klient ( CatalogService v příkladu) je aktivován pomocí příkazu di (vkládání závislostí), což znamená, že může přijmout jakoukoli registrovanou službu ve svém konstruktoru, kromě HttpClient .
Typový klient je efektivně přechodný objekt, což znamená, že se vytvoří nová instance pokaždé, když je potřeba jedna. HttpClientPři každém sestavení dostane novou instanci. HttpMessageHandlerObjekty ve fondu však jsou objekty, které jsou opakovaně používány více HttpClient instancemi.
Použití typových klientských tříd
Nakonec, jakmile máte implementované typové třídy, můžete je zaregistrovat a konfigurovat pomocí AddHttpClient() . Pak je můžete použít všude, kde mají služby vložené do DI. Například v kódu stránky Razor nebo kontroleru webové aplikace MVC, jako v následujícím kódu z eShopOnContainers:
namespace Microsoft.eShopOnContainers.WebMVC.Controllers
{
public class CatalogController : Controller
{
private ICatalogService _catalogSvc;
public CatalogController(ICatalogService catalogSvc) =>
_catalogSvc = catalogSvc;
public async Task<IActionResult> Index(int? BrandFilterApplied,
int? TypesFilterApplied,
int? page,
[FromQuery]string errorMsg)
{
var itemsPage = 10;
var catalog = await _catalogSvc.GetCatalogItems(page ?? 0,
itemsPage,
BrandFilterApplied,
TypesFilterApplied);
//… Additional code
}
}
}
Až do tohoto okamžiku byl výše uvedený fragment kódu zobrazen pouze jako příklad provádění běžných požadavků HTTP. Ale "Magic" přichází v následujících částech, kde se zobrazuje, jak všechny požadavky HTTP vytvořené nástrojem HttpClient můžou mít odolné zásady, jako jsou opakování exponenciálního omezení rychlostiu, přepínacích bodů, funkce zabezpečení s použitím ověřovacích tokenů nebo dokonce jakékoli jiné vlastní funkce. A všechny z nich je možné provést pouhým přidáním zásad a delegování obslužných rutin do registrovaných typových klientů.
Další zdroje informací
Používání HttpClientFactory v .NET
https://docs.microsoft.com/aspnet/core/fundamentals/http-requestszdrojový kód HttpClientFactory v
dotnet/extensionsúložišti GitHub
https://github.com/dotnet/extensions/tree/v3.1.8/src/HttpClientFactoryPolly (odolnost proti chybám .NET a knihovna pro zpracování s přechodnými chybami)
https://thepollyproject.azurewebsites.net/použití IHttpClientFactory bez injektáže závislosti (GitHub problém)
https://github.com/dotnet/extensions/issues/1345