Megjegyzés
Az oldalhoz való hozzáféréshez engedély szükséges. Megpróbálhat bejelentkezni vagy módosítani a címtárat.
Az oldalhoz való hozzáféréshez engedély szükséges. Megpróbálhatja módosítani a címtárat.
Note
Ez nem a cikk legújabb verziója. Az aktuális kiadásról a cikk .NET 10-es verziójában olvashat.
Warning
A ASP.NET Core ezen verziója már nem támogatott. További információt a .NET és a .NET Core támogatási szabályzatában talál. A jelen cikk .NET 9-es verzióját lásd az aktuális kiadásért .
Kirk Larkin, Steve Gordon, Glenn Condron és Ryan Nowak.
Egy IHttpClientFactory regisztrálható és használható HttpClient példányok konfigurálására és létrehozására egy alkalmazásban.
IHttpClientFactory a következő előnyöket kínálja:
- Központi helyet biztosít a logikai
HttpClient-példányok elnevezéséhez és konfigurálásához. Például egy github nevű ügyfél regisztrálható és konfigurálható a GitHub eléréséhez. Az alapértelmezett ügyfél regisztrálható az általános hozzáféréshez. - Kodifikálja a kimenő köztes szoftver fogalmát a
HttpClientdelegáló kezelők használatával. Bővítményeket biztosít a Polly-alapú köztes szoftverhez, hogy kihasználhassa a kezelők delegálásának előnyeit aHttpClient. - A mögöttes
HttpClientMessageHandlerpéldányok készletezését és élettartamát kezeli. Az automatikus felügyelet elkerüli az élettartamok manuális kezelésekorHttpClientelőforduló gyakori DNS-(tartománynévrendszer-) problémákat. - Konfigurálható naplózási felületet (via
ILogger) ad hozzá a gyár által létrehozott ügyfeleken keresztül küldött összes kéréshez.
A jelen témakör verziójának mintakódja a HTTP-válaszokban visszaadott JSON-tartalom deszerializálására szolgál System.Text.Json . Azoknál a mintáknál, amelyek Json.NET és ReadAsAsync<T>-et használnak, a verzióválasztóval válassza ki ennek a témakörnek a 2.x verzióját.
Használati minták
Az alkalmazásokban többféleképpen IHttpClientFactory is használható:
A legjobb módszer az alkalmazás követelményeitől függ.
Alapszintű használat
Regisztráljon IHttpClientFactory, hívja AddHttpClient a Program.cs-ban:
var builder = WebApplication.CreateBuilder(args);
// Add services to the container.
builder.Services.AddHttpClient();
Egy IHttpClientFactory kérhető függőséginjektálással (DI). A következő kód IHttpClientFactory-t használ egy HttpClient példány létrehozásához.
public class BasicModel : PageModel
{
private readonly IHttpClientFactory _httpClientFactory;
public BasicModel(IHttpClientFactory httpClientFactory) =>
_httpClientFactory = httpClientFactory;
public IEnumerable<GitHubBranch>? GitHubBranches { get; set; }
public async Task OnGet()
{
var httpRequestMessage = new HttpRequestMessage(
HttpMethod.Get,
"https://api.github.com/repos/dotnet/AspNetCore.Docs/branches")
{
Headers =
{
{ HeaderNames.Accept, "application/vnd.github.v3+json" },
{ HeaderNames.UserAgent, "HttpRequestsSample" }
}
};
var httpClient = _httpClientFactory.CreateClient();
var httpResponseMessage = await httpClient.SendAsync(httpRequestMessage);
if (httpResponseMessage.IsSuccessStatusCode)
{
using var contentStream =
await httpResponseMessage.Content.ReadAsStreamAsync();
GitHubBranches = await JsonSerializer.DeserializeAsync
<IEnumerable<GitHubBranch>>(contentStream);
}
}
}
Az előző példához hasonló használat IHttpClientFactory jó módszer egy meglévő alkalmazás újrabontására. Nincs hatással a használat módjára HttpClient . Azokon a helyeken, ahol HttpClient példányok jönnek létre egy meglévő alkalmazásban, cserélje le ezeket az előfordulásokat CreateClient hívásokkal.
Névvel ellátott ügyfelek
A nevesített ügyfelek akkor jó választásnak számítanak, ha:
- Az alkalmazásnak számos különböző módja van
HttpClienthasználatára. - Sok
HttpClientmás konfigurációval rendelkezik.
Adja meg az elnevezett HttpClient konfigurációját a Program.cs során végzett regisztrációkor:
builder.Services.AddHttpClient("GitHub", httpClient =>
{
httpClient.BaseAddress = new Uri("https://api.github.com/");
// using Microsoft.Net.Http.Headers;
// The GitHub API requires two headers.
httpClient.DefaultRequestHeaders.Add(
HeaderNames.Accept, "application/vnd.github.v3+json");
httpClient.DefaultRequestHeaders.Add(
HeaderNames.UserAgent, "HttpRequestsSample");
});
Az előző kódban az ügyfél a következőkkel van konfigurálva:
- Az alapcím
https://api.github.com/. - A GitHub API használatához két fejléc szükséges.
CreateClient
Minden alkalommal, amikor CreateClient hívásra kerül:
- Létrejön egy
HttpClientúj példány. - A rendszer meghívja a konfigurációs műveletet.
Névvel ellátott ügyfél létrehozásához adja át az ügyfél nevét a következőbe CreateClient:
public class NamedClientModel : PageModel
{
private readonly IHttpClientFactory _httpClientFactory;
public NamedClientModel(IHttpClientFactory httpClientFactory) =>
_httpClientFactory = httpClientFactory;
public IEnumerable<GitHubBranch>? GitHubBranches { get; set; }
public async Task OnGet()
{
var httpClient = _httpClientFactory.CreateClient("GitHub");
var httpResponseMessage = await httpClient.GetAsync(
"repos/dotnet/AspNetCore.Docs/branches");
if (httpResponseMessage.IsSuccessStatusCode)
{
using var contentStream =
await httpResponseMessage.Content.ReadAsStreamAsync();
GitHubBranches = await JsonSerializer.DeserializeAsync
<IEnumerable<GitHubBranch>>(contentStream);
}
}
}
Az előző kódban a kérésnek nem kell állomásnevet megadnia. A kód csak az elérési utat tudja átadni, mivel a rendszer az ügyfélhez konfigurált alapcímet használja.
Beírt ügyfelek
Beírt ügyfelek:
- A névvel ellátott ügyfelekkel azonos képességeket biztosíthat anélkül, hogy sztringeket kellene használnia kulcsként.
- Az IntelliSense és a fordító segítséget nyújtanak a kliensek használata során.
- Adjon meg egyetlen helyet egy adott
HttpClienthely konfigurálásához és használatához. Például használható egyetlen gépelt ügyfél:- Egyetlen háttérvégpont esetén.
- A végponttal kapcsolatos összes logika beágyazása.
- Együttműködhet a DI-vel, és szükség esetén injektálható az alkalmazásban.
A gépelt ügyfél egy HttpClient paramétert fogad el a konstruktorában.
public class GitHubService
{
private readonly HttpClient _httpClient;
public GitHubService(HttpClient httpClient)
{
_httpClient = httpClient;
_httpClient.BaseAddress = new Uri("https://api.github.com/");
// using Microsoft.Net.Http.Headers;
// The GitHub API requires two headers.
_httpClient.DefaultRequestHeaders.Add(
HeaderNames.Accept, "application/vnd.github.v3+json");
_httpClient.DefaultRequestHeaders.Add(
HeaderNames.UserAgent, "HttpRequestsSample");
}
public async Task<IEnumerable<GitHubBranch>?> GetAspNetCoreDocsBranchesAsync() =>
await _httpClient.GetFromJsonAsync<IEnumerable<GitHubBranch>>(
"repos/dotnet/AspNetCore.Docs/branches");
}
Az előző kódban:
- A konfiguráció át lesz helyezve a beírt ügyfélbe.
- A megadott
HttpClientpéldány privát mezőként van tárolva.
Olyan API-specifikus metódusok hozhatók létre, amelyek elérhetővé HttpClient teszik a funkciókat. A GetAspNetCoreDocsBranches módszer például kódokat kapszuláz, hogy dokumentációt kérjen le a GitHub-ágakból.
A következő kód AddHttpClient hívást a Program.cs-ben a GitHubService típusú ügyfélosztály regisztrálására használják:
builder.Services.AddHttpClient<GitHubService>();
A beírt ügyfél átmenetiként van regisztrálva a DI-ben. Az előző kódban AddHttpClient átmeneti szolgáltatásként regisztrál GitHubService . Ez a regisztráció egy gyári módszert használ a következő célokra:
- Hozza létre a
HttpClientegy példányát. - Hozzon létre egy
GitHubServicepéldányt, amelynek konstruktorába adja át aHttpClientpéldányt.
A beírt ügyfél közvetlenül injektálható és felhasználható:
public class TypedClientModel : PageModel
{
private readonly GitHubService _gitHubService;
public TypedClientModel(GitHubService gitHubService) =>
_gitHubService = gitHubService;
public IEnumerable<GitHubBranch>? GitHubBranches { get; set; }
public async Task OnGet()
{
try
{
GitHubBranches = await _gitHubService.GetAspNetCoreDocsBranchesAsync();
}
catch (HttpRequestException)
{
// ...
}
}
}
A típusos ügyfél konfigurációja a regisztráció Program.cs során is megadható a típusos ügyfél konstruktora helyett.
builder.Services.AddHttpClient<GitHubService>(httpClient =>
{
httpClient.BaseAddress = new Uri("https://api.github.com/");
// ...
});
Létrehozott ügyfelek
IHttpClientFactory külső kódtárakkal, például a Refittel együtt használható. A Refit egy REST .NET-kódtár. Az API-kat élő felületekké alakítja REST . Hívja meg a AddRefitClient-t egy felület dinamikus implementációjának létrehozásához, amely a HttpClient-t használja a külső HTTP-hívások végrehajtására.
Az egyéni felület a külső API-t jelöli:
public interface IGitHubClient
{
[Get("/repos/dotnet/AspNetCore.Docs/branches")]
Task<IEnumerable<GitHubBranch>> GetAspNetCoreDocsBranchesAsync();
}
Hívja meg AddRefitClient a dinamikus implementáció létrehozásához, majd hívja meg ConfigureHttpClient az alapjául szolgáló HttpClient konfigurálásához.
builder.Services.AddRefitClient<IGitHubClient>()
.ConfigureHttpClient(httpClient =>
{
httpClient.BaseAddress = new Uri("https://api.github.com/");
// using Microsoft.Net.Http.Headers;
// The GitHub API requires two headers.
httpClient.DefaultRequestHeaders.Add(
HeaderNames.Accept, "application/vnd.github.v3+json");
httpClient.DefaultRequestHeaders.Add(
HeaderNames.UserAgent, "HttpRequestsSample");
});
DI használatával érheti el a dinamikus implementációt IGitHubClient:
public class RefitModel : PageModel
{
private readonly IGitHubClient _gitHubClient;
public RefitModel(IGitHubClient gitHubClient) =>
_gitHubClient = gitHubClient;
public IEnumerable<GitHubBranch>? GitHubBranches { get; set; }
public async Task OnGet()
{
try
{
GitHubBranches = await _gitHubClient.GetAspNetCoreDocsBranchesAsync();
}
catch (ApiException)
{
// ...
}
}
}
POST, PUT és DELETE kérések létrehozása
Az előző példákban minden HTTP-kérés a GET HTTP parancsot használja.
HttpClient egyéb HTTP-parancsokat is támogat, többek között a következőket:
- POST
- PUT
- DELETE
- PATCH
A támogatott HTTP-parancsok teljes listáját lásd HttpMethod: .
Az alábbi példa bemutatja, hogyan lehet HTTP POST-kérelmet küldeni:
public async Task CreateItemAsync(TodoItem todoItem)
{
var todoItemJson = new StringContent(
JsonSerializer.Serialize(todoItem),
Encoding.UTF8,
Application.Json); // using static System.Net.Mime.MediaTypeNames;
using var httpResponseMessage =
await _httpClient.PostAsync("/api/TodoItems", todoItemJson);
httpResponseMessage.EnsureSuccessStatusCode();
}
Az előző kódban a CreateItemAsync metódus:
- Szerializálja a
TodoItemparamétert JSON formátumba, aSystem.Text.Jsonhasználatával. - Létrehoz egy példányt StringContent a szerializált JSON becsomagolásához a HTTP-kérés törzsébe való küldéshez.
- A JSON-tartalomnak a megadott URL-címre való elküldésére irányuló hívások PostAsync . Ez egy relatív URL-cím, amely hozzáadódik a HttpClient.BaseAddresshez.
- Ha a válasz állapotkódja nem jelzi a sikert, a hívás EnsureSuccessStatusCode kivételt jelez.
HttpClient más típusú tartalmakat is támogat. Például: MultipartContent és StreamContent. A támogatott tartalmak teljes listáját lásd HttpContent: .
Az alábbi példa egy HTTP PUT-kérést mutat be:
public async Task SaveItemAsync(TodoItem todoItem)
{
var todoItemJson = new StringContent(
JsonSerializer.Serialize(todoItem),
Encoding.UTF8,
Application.Json);
using var httpResponseMessage =
await _httpClient.PutAsync($"/api/TodoItems/{todoItem.Id}", todoItemJson);
httpResponseMessage.EnsureSuccessStatusCode();
}
Az előző kód hasonló a POST-példához. A SaveItemAsync metódus a PutAsync-t hívja, nem pedig a PostAsync-t.
Az alábbi példa egy HTTP DELETE-kérést mutat be:
public async Task DeleteItemAsync(long itemId)
{
using var httpResponseMessage =
await _httpClient.DeleteAsync($"/api/TodoItems/{itemId}");
httpResponseMessage.EnsureSuccessStatusCode();
}
Az előző kódban a DeleteItemAsync metódus meghívja a DeleteAsync metódust. Mivel a HTTP DELETE-kérelmek általában nem tartalmaznak törzset, a DeleteAsync metódus nem biztosít olyan túlterhelést, amely elfogad egy HttpContent példányt.
Ha többet szeretne megtudni a különböző HTTP-parancsok a HttpClient használatáról, látogasson el a(z) HttpClient oldalra.
Kimenő kérelem köztes szoftvere
HttpClient a kimenő HTTP-kérésekhez összekapcsolható kezelők delegálásának koncepciója.
IHttpClientFactory:
- Leegyszerűsíti az egyes elnevezett ügyfelekre alkalmazni kívánt kezelők meghatározását.
- Támogatja a több kezelő regisztrációját és láncolását egy kimenő kérelem köztesszoftver-folyamat létrehozásához. Ezek a kezelők a kimenő kérés előtt és után is el tudják végezni a munkát. Ez a minta:
- Hasonló az ASP.NET Core bejövő middleware-folyamatához.
- Mechanizmust biztosít a HTTP-kérelmekkel kapcsolatos horizontális problémák kezelésére, például:
- gyorsítótárazás
- hibakezelés
- szerializálás
- naplózás
Delegáló kezelő létrehozása:
- Származtasson innen: DelegatingHandler.
- Felülírás SendAsync. Hajtsa végre a kódot, mielőtt átadja a kérést a folyamat következő kezelőjének:
public class ValidateHeaderHandler : DelegatingHandler
{
protected override async Task<HttpResponseMessage> SendAsync(
HttpRequestMessage request, CancellationToken cancellationToken)
{
if (!request.Headers.Contains("X-API-KEY"))
{
return new HttpResponseMessage(HttpStatusCode.BadRequest)
{
Content = new StringContent(
"The API key header X-API-KEY is required.")
};
}
return await base.SendAsync(request, cancellationToken);
}
}
Az előző kód ellenőrzi, hogy a X-API-KEY fejléc szerepel-e a kérelemben. Ha X-API-KEY hiányzik, visszatér BadRequest.
Több kezelő is hozzáadható a következővel rendelkező HttpClientkonfigurációhozMicrosoft.Extensions.DependencyInjection.HttpClientBuilderExtensions.AddHttpMessageHandler:
builder.Services.AddTransient<ValidateHeaderHandler>();
builder.Services.AddHttpClient("HttpMessageHandler")
.AddHttpMessageHandler<ValidateHeaderHandler>();
Az előző kódban a ValidateHeaderHandler be van regisztrálva a DI-hez. A regisztráció után a AddHttpMessageHandler meghívható úgy, hogy megadjuk a kezelő típusát.
Több kezelő is regisztrálható abban a sorrendben, amelyet végre kell hajtaniuk. Minden kezelő burkolja a következő kezelőt, amíg végül a HttpClientHandler végrehajtja a kérést.
builder.Services.AddTransient<SampleHandler1>();
builder.Services.AddTransient<SampleHandler2>();
builder.Services.AddHttpClient("MultipleHttpMessageHandlers")
.AddHttpMessageHandler<SampleHandler1>()
.AddHttpMessageHandler<SampleHandler2>();
Az előző kódban előbb fut, SampleHandler1 mielőtt SampleHandler2.
A kimenő kérelem-middleware-ben használd a DI-t
Új delegálási kezelő létrehozásakor IHttpClientFactory a kezelő konstruktorparamétereinek teljesítéséhez a DI-t használja.
IHttpClientFactory
külön DI-hatókört hoz létre az egyes kezelők számára, ami meglepő viselkedéshez vezethet, ha egy kezelő egy hatókörön belüli szolgáltatást használ.
Vegyük például a következő felületet és annak implementációját, amely egy feladatot egy azonosítóval rendelkező műveletként jelöl: OperationId
public interface IOperationScoped
{
string OperationId { get; }
}
public class OperationScoped : IOperationScoped
{
public string OperationId { get; } = Guid.NewGuid().ToString()[^4..];
}
Ahogy a neve is sugallja, IOperationScoped egy hatókörön belüli élettartammal van regisztrálva a DI-ben :
builder.Services.AddScoped<IOperationScoped, OperationScoped>();
A következő delegáló kezelő felhasználja IOperationScoped az X-OPERATION-ID fejléc beállításához a kimenő kérésnél.
public class OperationHandler : DelegatingHandler
{
private readonly IOperationScoped _operationScoped;
public OperationHandler(IOperationScoped operationScoped) =>
_operationScoped = operationScoped;
protected override async Task<HttpResponseMessage> SendAsync(
HttpRequestMessage request, CancellationToken cancellationToken)
{
request.Headers.Add("X-OPERATION-ID", _operationScoped.OperationId);
return await base.SendAsync(request, cancellationToken);
}
}
A HttpRequestsSample letöltésben nyissa meg a /Operation-t, és frissítse az oldalt. A kérelem hatókörének értéke az egyes kérések esetében módosul, de a kezelő hatókörének értéke csak 5 másodpercenként változik.
A kezelők bármilyen hatókörű szolgáltatástól függhetnek. Azok a szolgáltatások, amelyektől a kezelők függenek, a kezelő ártalmatlanításakor lesznek megsemmisítve.
A kérésenkénti állapotok üzenetkezelőkkel való megosztásához használja az alábbi módszerek egyikét:
- Az adatokat a kezelőbe a HttpRequestMessage.Options használatával továbbítsa.
- Az aktuális kérés eléréséhez használható IHttpContextAccessor .
- Hozzon létre egy egyéni AsyncLocal<T> tárolóobjektumot az adatok továbbításához.
Polly-alapú kezelők használata
IHttpClientFactory integrálható a harmadik féltől származó Polly könyvtárral. A Polly egy átfogó rugalmassági és átmeneti hibakezelési kódtár a .NET-hez. Lehetővé teszi, hogy a fejlesztők folyékonyan és szálbiztosan fejezzék ki az olyan szabályzatokat, mint az Újrapróbálkozás, a Megszakító, az Időtúllépés, a Válaszfal elkülönítése és a Fallback.
A bővítménymetelyek lehetővé teszik a Polly-szabályzatok használatát konfigurált HttpClient példányokkal. A Polly-bővítmények támogatják a Polly-alapú kezelők ügyfelekhez való hozzáadását. A Pollyhoz a Microsoft.Extensions.Http.Polly NuGet csomag szükséges.
Átmeneti hibák kezelése
A hibák általában akkor fordulnak elő, ha a külső HTTP-hívások átmenetiek.
AddTransientHttpErrorPolicy lehetővé teszi, hogy egy szabályzat definiálva legyen az átmeneti hibák kezelésére. A következő válaszok kezelésére konfigurált AddTransientHttpErrorPolicy szabályzatok:
- HttpRequestException
- HTTP 5xx
- HTTP 408
AddTransientHttpErrorPolicy hozzáférést biztosít egy PolicyBuilder olyan objektumhoz, amely egy lehetséges átmeneti hibát jelképező hibák kezelésére van konfigurálva:
builder.Services.AddHttpClient("PollyWaitAndRetry")
.AddTransientHttpErrorPolicy(policyBuilder =>
policyBuilder.WaitAndRetryAsync(
3, retryNumber => TimeSpan.FromMilliseconds(600)));
Az előző kódban egy WaitAndRetryAsync szabályzat van definiálva. A sikertelen kérelmeket a rendszer akár háromszor is újrapróbálkozza a kísérletek között 600 ms késleltetéssel.
Szabályzatok dinamikus kiválasztása
A kiterjesztési metódusok például AddPolicyHandler Polly alapú kezelők hozzáadására szolgálnak. A következő AddPolicyHandler túlterhelési metódus (vagy függvény) vizsgálja meg a kérelmet annak eldöntésére, hogy melyik szabályzatot alkalmazza.
var timeoutPolicy = Policy.TimeoutAsync<HttpResponseMessage>(
TimeSpan.FromSeconds(10));
var longTimeoutPolicy = Policy.TimeoutAsync<HttpResponseMessage>(
TimeSpan.FromSeconds(30));
builder.Services.AddHttpClient("PollyDynamic")
.AddPolicyHandler(httpRequestMessage =>
httpRequestMessage.Method == HttpMethod.Get ? timeoutPolicy : longTimeoutPolicy);
Az előző kódban, ha a kimenő kérés HTTP GET, a rendszer 10 másodperces időtúllépést alkalmaz. Bármely más HTTP-metódus esetében 30 másodperces időtúllépést használunk.
Több Polly-kezelő hozzáadása
Gyakori a Polly-szabályok beágyazása.
builder.Services.AddHttpClient("PollyMultiple")
.AddTransientHttpErrorPolicy(policyBuilder =>
policyBuilder.RetryAsync(3))
.AddTransientHttpErrorPolicy(policyBuilder =>
policyBuilder.CircuitBreakerAsync(5, TimeSpan.FromSeconds(30)));
Az előző példában:
- A rendszer két kezelőt ad hozzá.
- Az első kezelő AddTransientHttpErrorPolicy segítségével ad hozzá egy újrapróbálkozási szabályzatot. A sikertelen kérelmeket a rendszer akár háromszor is újrapróbálkozza.
- A második
AddTransientHttpErrorPolicyhívás egy áramkör-megszakító házirendet ad hozzá. További külső kérések 30 másodpercig le lesznek tiltva, ha 5 sikertelen kísérlet egymás után történik. Az áramkör-megszakító házirendjei állapotalapúak. Az ügyfélen keresztüli összes hívás ugyanazt az áramkör állapotot osztja meg.
Szabályzatok hozzáadása a Polly-beállításjegyzékből
A rendszeresen használt szabályzatok kezelésének egyik módszere az, hogy egyszeri definiálásuk után regisztrálja azokat egy PolicyRegistry. Például:
var timeoutPolicy = Policy.TimeoutAsync<HttpResponseMessage>(
TimeSpan.FromSeconds(10));
var longTimeoutPolicy = Policy.TimeoutAsync<HttpResponseMessage>(
TimeSpan.FromSeconds(30));
var policyRegistry = builder.Services.AddPolicyRegistry();
policyRegistry.Add("Regular", timeoutPolicy);
policyRegistry.Add("Long", longTimeoutPolicy);
builder.Services.AddHttpClient("PollyRegistryRegular")
.AddPolicyHandlerFromRegistry("Regular");
builder.Services.AddHttpClient("PollyRegistryLong")
.AddPolicyHandlerFromRegistry("Long");
Az előző kódban:
- A Polly-beállításjegyzékhez két házirendet
RegularésLongadnak hozzá. - AddPolicyHandlerFromRegistry az egyes elnevezett ügyfeleket úgy konfigurálja, hogy ezeket a házirendeket a Polly-beállításjegyzékből használják.
További információért a IHttpClientFactory és a Polly-integrációkról, lásd a Polly wiki oldalt.
HttpClient és élettartam-kezelése
Minden alkalommal egy új HttpClient példányt ad vissza, amikor a CreateClient-n meghívják a IHttpClientFactory-t. Nevesített ügyfelenként jön létre egy HttpMessageHandler. A gyár kezeli az HttpMessageHandler példányok élettartamát.
IHttpClientFactory összegyűjti a gyár által létrehozott HttpMessageHandler példányokat az erőforrás-felhasználás csökkentése érdekében. A HttpMessageHandler példányok újra felhasználhatók a készletből egy új HttpClient példány létrehozásakor, ha az élettartama még nem járt le.
A kezelők készletezése kívánatos, mivel az egyes kezelők általában saját mögöttes HTTP-kapcsolatokat kezelnek. Ha a szükségesnél több kezelőt hoz létre, az a kapcsolat késéséhez vezethet. Egyes kezelők emellett határozatlan ideig nyitva tartják a kapcsolatokat, ami megakadályozhatja, hogy a kezelő reagáljon a DNS (tartománynévrendszer) változásaira.
Az alapértelmezett kezelő élettartama két perc. Az alapértelmezett érték felülírható nevesített ügyfél alapján:
builder.Services.AddHttpClient("HandlerLifetime")
.SetHandlerLifetime(TimeSpan.FromMinutes(5));
HttpClient a példányok általában olyan .NET-objektumokként kezelhetők, amelyek nem igényelnek ártalmatlanítást. A felszabadítás megszakítja a kimenő kérelmeket, és garantálja, hogy az adott HttpClient példány nem használható a hívás után Dispose.
IHttpClientFactory nyomon követi és megsemmisíti a HttpClient példányok által használt erőforrásokat.
Egyetlen HttpClient példány hosszú ideig történő életben tartása IHttpClientFactory bevezetése előtti gyakori minta. Ez a minta szükségtelenné válik az IHttpClientFactory rendszerre történő migrálás után.
Az IHttpClientFactory alternatívái
A DI-kompatibilis alkalmazások használata IHttpClientFactory elkerüli a következőt:
- Erőforrás-kimerülési problémák az
HttpMessageHandlerpéldányok összevonásával. - Régi DNS-problémákat orvosolhatunk az
HttpMessageHandlerpéldányok rendszeres időközönkénti újraindításával.
Az előző problémákat többféleképpen is meg lehet oldani egy hosszú élettartamú SocketsHttpHandler példány használatával.
- Hozzon létre egy
SocketsHttpHandlerpéldányt, amikor az alkalmazás elindul, és használja azt az alkalmazás teljes élettartama alatt. - Konfiguráljon PooledConnectionLifetime egy megfelelő értékre a DNS frissítési ideje alapján.
- Hozzon létre
HttpClientpéldányokatnew HttpClient(handler, disposeHandler: false)szükség szerint.
Az előző megközelítések hasonló módon oldják meg azokat az erőforrás-kezelési problémákat, amelyeket a IHttpClientFactory megold.
- A
SocketsHttpHandlermegosztja a kapcsolatokat aHttpClientpéldányok között. Ez a megosztás megakadályozza a foglalatok kimerülését. - A
SocketsHttpHandlera kapcsolatokatPooledConnectionLifetimeszerint ciklusokba rendezi az elavult DNS-problémák elkerülése érdekében.
Logging
Az ügyfelek, akik a IHttpClientFactory segítségével lettek létrehozva, naplóüzeneteket rögzítenek az összes kéréshez. A naplózási konfigurációban engedélyezze a megfelelő információs szintet az alapértelmezett naplóüzenetek megtekintéséhez. A további naplózás, például a kérelemfejlécek naplózása csak nyomkövetési szinten szerepel.
Az egyes ügyfelekhez használt naplókategória tartalmazza az ügyfél nevét. Egy MyNamedClient nevű ügyfél például naplózza a "System.Net.Http.HttpClient" kategóriával rendelkező üzeneteket. MyNamedClient. LogicalHandler". A LogicalHandlerrel utótaggal ellátott üzenetek a kérelemkezelő folyamaton kívülre kerülnek. A kéréskor a rendszer az üzeneteket naplózza, mielőtt a folyamat többi kezelője feldolgozta volna. A válaszban az üzenetek naplózva lesznek, miután bármely más folyamatkezelő megkapta a választ.
A naplózás a kérelemkezelő folyamaton belül is megtörténik. A MyNamedClient példában ezek az üzenetek a "System.Net.Http.HttpClient" naplókategória szerint vannak naplózva. MyNamedClient. ClientHandler". A kérés esetében ez az összes többi kezelő lefutása után, és közvetlenül a kérés elküldése előtt fordul elő. A válaszban ez a naplózás a válasz állapotát is tartalmazza, mielőtt az áthalad a kezelőfolyamaton.
A folyamaton kívüli és a folyamaton belüli naplózás engedélyezése lehetővé teszi a többi folyamatkezelő által végrehajtott módosítások ellenőrzését. Ez a kérelemfejlécek vagy a válaszállapot-kód módosításait is tartalmazhatja.
Az ügyfél nevének beleszámításával a naplókategória lehetővé teszi a naplószűrést adott nevesített ügyfelek esetében.
A HttpMessageHandler konfigurálása
Szükség lehet az ügyfél által használt belső HttpMessageHandler konfiguráció szabályozására.
A rendszer névvel ellátott vagy beírt ügyfelek hozzáadásakor ad vissza egy IHttpClientBuilder hibát. A ConfigurePrimaryHttpMessageHandler bővítménymetódus használható meghatalmazott definiálására. A meghatalmazott az ügyfél által használt elsődleges HttpMessageHandler kiszolgáló létrehozásához és konfigurálásához használható:
builder.Services.AddHttpClient("ConfiguredHttpMessageHandler")
.ConfigurePrimaryHttpMessageHandler(() =>
new HttpClientHandler
{
AllowAutoRedirect = true,
UseDefaultCredentials = true
});
Cookies
A készletezett HttpMessageHandler példányoknál CookieContainer objektumok megosztása történik. A nem várt CookieContainer objektummegosztás gyakran helytelen kódot eredményez. A cookie-kat igénylő alkalmazások esetében fontolja meg az alábbiakat:
- Az automatikus cookie kezelés letiltása
- Elkerülve
IHttpClientFactory
Hívás ConfigurePrimaryHttpMessageHandler az automatikus cookie kezelés letiltására:
builder.Services.AddHttpClient("NoAutomaticCookies")
.ConfigurePrimaryHttpMessageHandler(() =>
new HttpClientHandler
{
UseCookies = false
});
Az IHttpClientFactory használata konzolalkalmazásban
Egy konzolalkalmazásban adja hozzá a következő csomaghivatkozásokat a projekthez:
Az alábbi példában:
-
IHttpClientFactory és
GitHubServiceregisztrálva vannak az Általános Gazdagép szolgáltatástárolójában. - A
GitHubService-t a DI kéri, amely viszont egy példányt kér aIHttpClientFactory-ből. -
GitHubServiceIHttpClientFactory-t használ, hogy létrehozzon egyHttpClientpéldányt, amit a GitHub dokumentumok ágainak lekérésére használ.
using System.Text.Json;
using System.Text.Json.Serialization;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging;
var host = new HostBuilder()
.ConfigureServices(services =>
{
services.AddHttpClient();
services.AddTransient<GitHubService>();
})
.Build();
try
{
var gitHubService = host.Services.GetRequiredService<GitHubService>();
var gitHubBranches = await gitHubService.GetAspNetCoreDocsBranchesAsync();
Console.WriteLine($"{gitHubBranches?.Count() ?? 0} GitHub Branches");
if (gitHubBranches is not null)
{
foreach (var gitHubBranch in gitHubBranches)
{
Console.WriteLine($"- {gitHubBranch.Name}");
}
}
}
catch (Exception ex)
{
host.Services.GetRequiredService<ILogger<Program>>()
.LogError(ex, "Unable to load branches from GitHub.");
}
public class GitHubService
{
private readonly IHttpClientFactory _httpClientFactory;
public GitHubService(IHttpClientFactory httpClientFactory) =>
_httpClientFactory = httpClientFactory;
public async Task<IEnumerable<GitHubBranch>?> GetAspNetCoreDocsBranchesAsync()
{
var httpRequestMessage = new HttpRequestMessage(
HttpMethod.Get,
"https://api.github.com/repos/dotnet/AspNetCore.Docs/branches")
{
Headers =
{
{ "Accept", "application/vnd.github.v3+json" },
{ "User-Agent", "HttpRequestsConsoleSample" }
}
};
var httpClient = _httpClientFactory.CreateClient();
var httpResponseMessage = await httpClient.SendAsync(httpRequestMessage);
httpResponseMessage.EnsureSuccessStatusCode();
using var contentStream =
await httpResponseMessage.Content.ReadAsStreamAsync();
return await JsonSerializer.DeserializeAsync
<IEnumerable<GitHubBranch>>(contentStream);
}
}
public record GitHubBranch(
[property: JsonPropertyName("name")] string Name);
Élőfej propagálása köztes szoftver
A fejléc átvitele egy ASP.NET Core middleware, amely a HTTP-fejléceket átviszi a bejövő kérésből a kimenő HttpClient kérésekbe. A fejlécpropagálás használata:
Telepítse a Microsoft.AspNetCore.HeaderPropagation csomagot.
Konfigurálja a
HttpClient-t és a köztesszoftver-folyamatot aProgram.cs-ben.// Add services to the container. builder.Services.AddControllers(); builder.Services.AddHttpClient("PropagateHeaders") .AddHeaderPropagation(); builder.Services.AddHeaderPropagation(options => { options.Headers.Add("X-TraceId"); }); var app = builder.Build(); // Configure the HTTP request pipeline. app.UseHttpsRedirection(); app.UseHeaderPropagation(); app.MapControllers();Kimenő kérések létrehozása a konfigurált
HttpClientpéldány használatával, amely tartalmazza a hozzáadott fejléceket.
További erőforrások
- Mintakód megtekintése vagy letöltése (hogyan töltsd le)
- Rugalmas HTTP-kérések implementálása a HttpClientFactory használatával
- HTTP-hívás újrapróbálkozások implementálása exponenciális visszalépéssel HttpClientFactory és Polly szabályzatokkal
- Az áramkör-megszakító minta implementálása
- JSON szerializálása és deszerializálása a .NET-ben
Kirk Larkin, Steve Gordon, Glenn Condron és Ryan Nowak.
Egy IHttpClientFactory regisztrálható és használható HttpClient példányok konfigurálására és létrehozására egy alkalmazásban.
IHttpClientFactory a következő előnyöket kínálja:
- Központi helyet biztosít a logikai
HttpClient-példányok elnevezéséhez és konfigurálásához. Például egy github nevű ügyfél regisztrálható és konfigurálható a GitHub eléréséhez. Az alapértelmezett ügyfél regisztrálható az általános hozzáféréshez. - Kodifikálja a kimenő köztes szoftver fogalmát a
HttpClientdelegáló kezelők használatával. Bővítményeket biztosít a Polly-alapú köztes szoftverhez, hogy kihasználhassa a kezelők delegálásának előnyeit aHttpClient. - A mögöttes
HttpClientMessageHandlerpéldányok készletezését és élettartamát kezeli. Az automatikus felügyelet elkerüli az élettartamok manuális kezelésekorHttpClientelőforduló gyakori DNS-(tartománynévrendszer-) problémákat. - Konfigurálható naplózási felületet (via
ILogger) ad hozzá a gyár által létrehozott ügyfeleken keresztül küldött összes kéréshez.
Mintakód megtekintése vagy letöltése (hogyan töltsük le).
A jelen témakör verziójának mintakódja a HTTP-válaszokban visszaadott JSON-tartalom deszerializálására szolgál System.Text.Json . Azoknál a mintáknál, amelyek Json.NET és ReadAsAsync<T>-et használnak, a verzióválasztóval válassza ki ennek a témakörnek a 2.x verzióját.
Használati minták
Az alkalmazásokban többféleképpen IHttpClientFactory is használható:
A legjobb módszer az alkalmazás követelményeitől függ.
Alapszintű használat
IHttpClientFactory a következő hívással AddHttpClientregisztrálható:
public class Startup
{
public Startup(IConfiguration configuration)
{
Configuration = configuration;
}
public IConfiguration Configuration { get; }
public void ConfigureServices(IServiceCollection services)
{
services.AddHttpClient();
// Remaining code deleted for brevity.
Egy IHttpClientFactory kérhető függőséginjektálással (DI). A következő kód IHttpClientFactory-t használ egy HttpClient példány létrehozásához.
public class BasicUsageModel : PageModel
{
private readonly IHttpClientFactory _clientFactory;
public IEnumerable<GitHubBranch> Branches { get; private set; }
public bool GetBranchesError { get; private set; }
public BasicUsageModel(IHttpClientFactory clientFactory)
{
_clientFactory = clientFactory;
}
public async Task OnGet()
{
var request = new HttpRequestMessage(HttpMethod.Get,
"https://api.github.com/repos/dotnet/AspNetCore.Docs/branches");
request.Headers.Add("Accept", "application/vnd.github.v3+json");
request.Headers.Add("User-Agent", "HttpClientFactory-Sample");
var client = _clientFactory.CreateClient();
var response = await client.SendAsync(request);
if (response.IsSuccessStatusCode)
{
using var responseStream = await response.Content.ReadAsStreamAsync();
Branches = await JsonSerializer.DeserializeAsync
<IEnumerable<GitHubBranch>>(responseStream);
}
else
{
GetBranchesError = true;
Branches = Array.Empty<GitHubBranch>();
}
}
}
Az előző példához hasonló használat IHttpClientFactory jó módszer egy meglévő alkalmazás újrabontására. Nincs hatással a használat módjára HttpClient . Azokon a helyeken, ahol HttpClient példányok jönnek létre egy meglévő alkalmazásban, cserélje le ezeket az előfordulásokat CreateClient hívásokkal.
Névvel ellátott ügyfelek
A nevesített ügyfelek akkor jó választásnak számítanak, ha:
- Az alkalmazásnak számos különböző módja van
HttpClienthasználatára. - Sok
HttpClientmás konfigurációval rendelkezik.
Egy megnevezett HttpClient konfigurációja meghatározható a következő helyen, regisztráció során: Startup.ConfigureServices.
services.AddHttpClient("github", c =>
{
c.BaseAddress = new Uri("https://api.github.com/");
// Github API versioning
c.DefaultRequestHeaders.Add("Accept", "application/vnd.github.v3+json");
// Github requires a user-agent
c.DefaultRequestHeaders.Add("User-Agent", "HttpClientFactory-Sample");
});
Az előző kódban az ügyfél a következőkkel van konfigurálva:
- Az alapcím
https://api.github.com/. - A GitHub API használatához két fejléc szükséges.
CreateClient
Minden alkalommal, amikor CreateClient hívásra kerül:
- Létrejön egy
HttpClientúj példány. - A rendszer meghívja a konfigurációs műveletet.
Névvel ellátott ügyfél létrehozásához adja át az ügyfél nevét a következőbe CreateClient:
public class NamedClientModel : PageModel
{
private readonly IHttpClientFactory _clientFactory;
public IEnumerable<GitHubPullRequest> PullRequests { get; private set; }
public bool GetPullRequestsError { get; private set; }
public bool HasPullRequests => PullRequests.Any();
public NamedClientModel(IHttpClientFactory clientFactory)
{
_clientFactory = clientFactory;
}
public async Task OnGet()
{
var request = new HttpRequestMessage(HttpMethod.Get,
"repos/dotnet/AspNetCore.Docs/pulls");
var client = _clientFactory.CreateClient("github");
var response = await client.SendAsync(request);
if (response.IsSuccessStatusCode)
{
using var responseStream = await response.Content.ReadAsStreamAsync();
PullRequests = await JsonSerializer.DeserializeAsync
<IEnumerable<GitHubPullRequest>>(responseStream);
}
else
{
GetPullRequestsError = true;
PullRequests = Array.Empty<GitHubPullRequest>();
}
}
}
Az előző kódban a kérésnek nem kell állomásnevet megadnia. A kód csak az elérési utat tudja átadni, mivel a rendszer az ügyfélhez konfigurált alapcímet használja.
Beírt ügyfelek
Beírt ügyfelek:
- A névvel ellátott ügyfelekkel azonos képességeket biztosíthat anélkül, hogy sztringeket kellene használnia kulcsként.
- Az IntelliSense és a fordító segítséget nyújtanak a kliensek használata során.
- Adjon meg egyetlen helyet egy adott
HttpClienthely konfigurálásához és használatához. Például használható egyetlen gépelt ügyfél:- Egyetlen háttérvégpont esetén.
- A végponttal kapcsolatos összes logika beágyazása.
- Együttműködhet a DI-vel, és szükség esetén injektálható az alkalmazásban.
A gépelt ügyfél egy HttpClient paramétert fogad el a konstruktorában.
public class GitHubService
{
public HttpClient Client { get; }
public GitHubService(HttpClient client)
{
client.BaseAddress = new Uri("https://api.github.com/");
// GitHub API versioning
client.DefaultRequestHeaders.Add("Accept",
"application/vnd.github.v3+json");
// GitHub requires a user-agent
client.DefaultRequestHeaders.Add("User-Agent",
"HttpClientFactory-Sample");
Client = client;
}
public async Task<IEnumerable<GitHubIssue>> GetAspNetDocsIssues()
{
return await Client.GetFromJsonAsync<IEnumerable<GitHubIssue>>(
"/repos/aspnet/AspNetCore.Docs/issues?state=open&sort=created&direction=desc");
}
}
Az előző kódban:
- A konfiguráció át lesz helyezve a beírt ügyfélbe.
- Az
HttpClientobjektum nyilvános tulajdonságként van közzétéve.
Olyan API-specifikus metódusok hozhatók létre, amelyek elérhetővé HttpClient teszik a funkciókat. Az GetAspNetDocsIssues például kódot ágyaz be a nyitott problémák lekéréséhez.
A következő kód meghívja a AddHttpClient a/t Startup.ConfigureServices-ben/-ban egy típusos ügyfélosztály regisztrálására:
services.AddHttpClient<GitHubService>();
A beírt ügyfél átmenetiként van regisztrálva a DI-ben. Az előző kódban AddHttpClient átmeneti szolgáltatásként regisztrál GitHubService . Ez a regisztráció egy gyári módszert használ a következő célokra:
- Hozza létre a
HttpClientegy példányát. - Hozzon létre egy
GitHubServicepéldányt, amelynek konstruktorába adja át aHttpClientpéldányt.
A beírt ügyfél közvetlenül injektálható és felhasználható:
public class TypedClientModel : PageModel
{
private readonly GitHubService _gitHubService;
public IEnumerable<GitHubIssue> LatestIssues { get; private set; }
public bool HasIssue => LatestIssues.Any();
public bool GetIssuesError { get; private set; }
public TypedClientModel(GitHubService gitHubService)
{
_gitHubService = gitHubService;
}
public async Task OnGet()
{
try
{
LatestIssues = await _gitHubService.GetAspNetDocsIssues();
}
catch(HttpRequestException)
{
GetIssuesError = true;
LatestIssues = Array.Empty<GitHubIssue>();
}
}
}
A típusos kliens konfigurációja a regisztráció Startup.ConfigureServices során adható meg, nem pedig a típusos kliens konstruktorában.
services.AddHttpClient<RepoService>(c =>
{
c.BaseAddress = new Uri("https://api.github.com/");
c.DefaultRequestHeaders.Add("Accept", "application/vnd.github.v3+json");
c.DefaultRequestHeaders.Add("User-Agent", "HttpClientFactory-Sample");
});
A HttpClient típusos kliensben beágyazható. Ahelyett, hogy tulajdonságként felfedte volna, definiáljon egy metódust, amely belsőleg hívja meg a HttpClient példányt:
public class RepoService
{
// _httpClient isn't exposed publicly
private readonly HttpClient _httpClient;
public RepoService(HttpClient client)
{
_httpClient = client;
}
public async Task<IEnumerable<string>> GetRepos()
{
var response = await _httpClient.GetAsync("aspnet/repos");
response.EnsureSuccessStatusCode();
using var responseStream = await response.Content.ReadAsStreamAsync();
return await JsonSerializer.DeserializeAsync
<IEnumerable<string>>(responseStream);
}
}
Az előző kódban a rendszer egy privát mezőben tárolja az HttpClient adatokat. A hozzáférés a HttpClient nyilvános GetRepos módszer szerint történik.
Létrehozott ügyfelek
IHttpClientFactory külső kódtárakkal, például a Refittel együtt használható. A Refit egy REST .NET-kódtár. Az API-kat élő felületekké alakítja REST . Az interfész implementációját a RestService dinamikusan hozza létre, miközben a HttpClient külső HTTP-hívások végrehajtására szolgál.
Egy felület és egy válasz definiálva van, amely a külső API-t és annak válaszát jelöli:
public interface IHelloClient
{
[Get("/helloworld")]
Task<Reply> GetMessageAsync();
}
public class Reply
{
public string Message { get; set; }
}
Egy beírt ügyfél hozzáadható a Refit használatával a megvalósítás létrehozásához:
public void ConfigureServices(IServiceCollection services)
{
services.AddHttpClient("hello", c =>
{
c.BaseAddress = new Uri("http://localhost:5000");
})
.AddTypedClient(c => Refit.RestService.For<IHelloClient>(c));
services.AddControllers();
}
A definiált felület szükség esetén felhasználható a DI és a Refit által biztosított implementációval:
[ApiController]
public class ValuesController : ControllerBase
{
private readonly IHelloClient _client;
public ValuesController(IHelloClient client)
{
_client = client;
}
[HttpGet("/")]
public async Task<ActionResult<Reply>> Index()
{
return await _client.GetMessageAsync();
}
}
POST, PUT és DELETE kérések létrehozása
Az előző példákban minden HTTP-kérés a GET HTTP parancsot használja.
HttpClient egyéb HTTP-parancsokat is támogat, többek között a következőket:
- POST
- PUT
- DELETE
- PATCH
A támogatott HTTP-parancsok teljes listáját lásd HttpMethod: .
Az alábbi példa bemutatja, hogyan lehet HTTP POST-kérelmet küldeni:
public async Task CreateItemAsync(TodoItem todoItem)
{
var todoItemJson = new StringContent(
JsonSerializer.Serialize(todoItem, _jsonSerializerOptions),
Encoding.UTF8,
"application/json");
using var httpResponse =
await _httpClient.PostAsync("/api/TodoItems", todoItemJson);
httpResponse.EnsureSuccessStatusCode();
}
Az előző kódban a CreateItemAsync metódus:
- Szerializálja a
TodoItemparamétert JSON formátumba, aSystem.Text.Jsonhasználatával. A szerializálási folyamat konfigurálásához a JsonSerializerOptions egy példányát használja. - Létrehoz egy példányt StringContent a szerializált JSON becsomagolásához a HTTP-kérés törzsébe való küldéshez.
- A JSON-tartalomnak a megadott URL-címre való elküldésére irányuló hívások PostAsync . Ez egy relatív URL-cím, amely hozzáadódik a HttpClient.BaseAddresshez.
- Felhívja EnsureSuccessStatusCode-t, hogy kivételt váltson ki, ha a válasz állapotkódja nem jelzi a sikert.
HttpClient más típusú tartalmakat is támogat. Például: MultipartContent és StreamContent. A támogatott tartalmak teljes listáját lásd HttpContent: .
Az alábbi példa egy HTTP PUT-kérést mutat be:
public async Task SaveItemAsync(TodoItem todoItem)
{
var todoItemJson = new StringContent(
JsonSerializer.Serialize(todoItem),
Encoding.UTF8,
"application/json");
using var httpResponse =
await _httpClient.PutAsync($"/api/TodoItems/{todoItem.Id}", todoItemJson);
httpResponse.EnsureSuccessStatusCode();
}
Az előző kód nagyon hasonlít a POST-példához. A SaveItemAsync metódus a PutAsync-t hívja, nem pedig a PostAsync-t.
Az alábbi példa egy HTTP DELETE-kérést mutat be:
public async Task DeleteItemAsync(long itemId)
{
using var httpResponse =
await _httpClient.DeleteAsync($"/api/TodoItems/{itemId}");
httpResponse.EnsureSuccessStatusCode();
}
Az előző kódban a DeleteItemAsync metódus meghívja a DeleteAsync metódust. Mivel a HTTP DELETE-kérelmek általában nem tartalmaznak törzset, a DeleteAsync metódus nem biztosít olyan túlterhelést, amely elfogad egy HttpContent példányt.
Ha többet szeretne megtudni a különböző HTTP-parancsok a HttpClient használatáról, látogasson el a(z) HttpClient oldalra.
Kimenő kérelem köztes szoftvere
HttpClient a kimenő HTTP-kérésekhez összekapcsolható kezelők delegálásának koncepciója.
IHttpClientFactory:
- Leegyszerűsíti az egyes elnevezett ügyfelekre alkalmazni kívánt kezelők meghatározását.
- Támogatja a több kezelő regisztrációját és láncolását egy kimenő kérelem köztesszoftver-folyamat létrehozásához. Ezek a kezelők a kimenő kérés előtt és után is el tudják végezni a munkát. Ez a minta:
- Hasonló az ASP.NET Core bejövő middleware-folyamatához.
- Mechanizmust biztosít a HTTP-kérelmekkel kapcsolatos horizontális problémák kezelésére, például:
- gyorsítótárazás
- hibakezelés
- szerializálás
- naplózás
Delegáló kezelő létrehozása:
- Származtasson innen: DelegatingHandler.
- Felülírás SendAsync. Hajtsa végre a kódot, mielőtt átadja a kérést a folyamat következő kezelőjének:
public class ValidateHeaderHandler : DelegatingHandler
{
protected override async Task<HttpResponseMessage> SendAsync(
HttpRequestMessage request,
CancellationToken cancellationToken)
{
if (!request.Headers.Contains("X-API-KEY"))
{
return new HttpResponseMessage(HttpStatusCode.BadRequest)
{
Content = new StringContent(
"You must supply an API key header called X-API-KEY")
};
}
return await base.SendAsync(request, cancellationToken);
}
}
Az előző kód ellenőrzi, hogy a X-API-KEY fejléc szerepel-e a kérelemben. Ha X-API-KEY hiányzik, visszatér BadRequest.
Több kezelő is hozzáadható a következővel rendelkező HttpClientkonfigurációhozMicrosoft.Extensions.DependencyInjection.HttpClientBuilderExtensions.AddHttpMessageHandler:
public void ConfigureServices(IServiceCollection services)
{
services.AddTransient<ValidateHeaderHandler>();
services.AddHttpClient("externalservice", c =>
{
// Assume this is an "external" service which requires an API KEY
c.BaseAddress = new Uri("https://localhost:5001/");
})
.AddHttpMessageHandler<ValidateHeaderHandler>();
// Remaining code deleted for brevity.
Az előző kódban a ValidateHeaderHandler be van regisztrálva a DI-hez. A regisztráció után a AddHttpMessageHandler meghívható úgy, hogy megadjuk a kezelő típusát.
Több kezelő is regisztrálható abban a sorrendben, amelyet végre kell hajtaniuk. Minden kezelő burkolja a következő kezelőt, amíg végül a HttpClientHandler végrehajtja a kérést.
services.AddTransient<SecureRequestHandler>();
services.AddTransient<RequestDataHandler>();
services.AddHttpClient("clientwithhandlers")
// This handler is on the outside and called first during the
// request, last during the response.
.AddHttpMessageHandler<SecureRequestHandler>()
// This handler is on the inside, closest to the request being
// sent.
.AddHttpMessageHandler<RequestDataHandler>();
A kimenő kérelem-middleware-ben használd a DI-t
Új delegálási kezelő létrehozásakor IHttpClientFactory a kezelő konstruktorparamétereinek teljesítéséhez a DI-t használja.
IHttpClientFactory
külön DI-hatókört hoz létre az egyes kezelők számára, ami meglepő viselkedéshez vezethet, ha egy kezelő egy hatókörön belüli szolgáltatást használ.
Vegyük például a következő felületet és annak implementációját, amely egy feladatot egy azonosítóval rendelkező műveletként jelöl: OperationId
public interface IOperationScoped
{
string OperationId { get; }
}
public class OperationScoped : IOperationScoped
{
public string OperationId { get; } = Guid.NewGuid().ToString()[^4..];
}
Ahogy a neve is sugallja, IOperationScoped egy hatókörön belüli élettartammal van regisztrálva a DI-ben :
public void ConfigureServices(IServiceCollection services)
{
services.AddDbContext<TodoContext>(options =>
options.UseInMemoryDatabase("TodoItems"));
services.AddHttpContextAccessor();
services.AddHttpClient<TodoClient>((sp, httpClient) =>
{
var httpRequest = sp.GetRequiredService<IHttpContextAccessor>().HttpContext.Request;
// For sample purposes, assume TodoClient is used in the context of an incoming request.
httpClient.BaseAddress = new Uri(UriHelper.BuildAbsolute(httpRequest.Scheme,
httpRequest.Host, httpRequest.PathBase));
httpClient.Timeout = TimeSpan.FromSeconds(5);
});
services.AddScoped<IOperationScoped, OperationScoped>();
services.AddTransient<OperationHandler>();
services.AddTransient<OperationResponseHandler>();
services.AddHttpClient("Operation")
.AddHttpMessageHandler<OperationHandler>()
.AddHttpMessageHandler<OperationResponseHandler>()
.SetHandlerLifetime(TimeSpan.FromSeconds(5));
services.AddControllers();
services.AddRazorPages();
}
A következő delegáló kezelő felhasználja IOperationScoped az X-OPERATION-ID fejléc beállításához a kimenő kérésnél.
public class OperationHandler : DelegatingHandler
{
private readonly IOperationScoped _operationService;
public OperationHandler(IOperationScoped operationScoped)
{
_operationService = operationScoped;
}
protected async override Task<HttpResponseMessage> SendAsync(
HttpRequestMessage request, CancellationToken cancellationToken)
{
request.Headers.Add("X-OPERATION-ID", _operationService.OperationId);
return await base.SendAsync(request, cancellationToken);
}
}
HttpRequestsSample A letöltésben keresse meg /Operation és frissítse a lapot. A kérelem hatókörének értéke az egyes kérések esetében módosul, de a kezelő hatókörének értéke csak 5 másodpercenként változik.
A kezelők bármilyen hatókörű szolgáltatástól függhetnek. Azok a szolgáltatások, amelyektől a kezelők függenek, a kezelő ártalmatlanításakor lesznek megsemmisítve.
A kérésenkénti állapotok üzenetkezelőkkel való megosztásához használja az alábbi módszerek egyikét:
- Az adatokat a kezelőbe a HttpRequestMessage.Options használatával továbbítsa.
- Az aktuális kérés eléréséhez használható IHttpContextAccessor .
- Hozzon létre egy egyéni AsyncLocal<T> tárolóobjektumot az adatok továbbításához.
Polly-alapú kezelők használata
IHttpClientFactory integrálható a harmadik féltől származó Polly könyvtárral. A Polly egy átfogó rugalmassági és átmeneti hibakezelési kódtár a .NET-hez. Lehetővé teszi, hogy a fejlesztők folyékonyan és szálbiztosan fejezzék ki az olyan szabályzatokat, mint az Újrapróbálkozás, a Megszakító, az Időtúllépés, a Válaszfal elkülönítése és a Fallback.
A bővítménymetelyek lehetővé teszik a Polly-szabályzatok használatát konfigurált HttpClient példányokkal. A Polly-bővítmények támogatják a Polly-alapú kezelők ügyfelekhez való hozzáadását. A Pollyhoz a Microsoft.Extensions.Http.Polly NuGet csomag szükséges.
Átmeneti hibák kezelése
A hibák általában akkor fordulnak elő, ha a külső HTTP-hívások átmenetiek.
AddTransientHttpErrorPolicy lehetővé teszi, hogy egy szabályzat definiálva legyen az átmeneti hibák kezelésére. A következő válaszok kezelésére konfigurált AddTransientHttpErrorPolicy szabályzatok:
- HttpRequestException
- HTTP 5xx
- HTTP 408
AddTransientHttpErrorPolicy hozzáférést biztosít egy PolicyBuilder olyan objektumhoz, amely egy lehetséges átmeneti hibát jelképező hibák kezelésére van konfigurálva:
public void ConfigureServices(IServiceCollection services)
{
services.AddHttpClient<UnreliableEndpointCallerService>()
.AddTransientHttpErrorPolicy(p =>
p.WaitAndRetryAsync(3, _ => TimeSpan.FromMilliseconds(600)));
// Remaining code deleted for brevity.
Az előző kódban egy WaitAndRetryAsync szabályzat van definiálva. A sikertelen kérelmeket a rendszer akár háromszor is újrapróbálkozza a kísérletek között 600 ms késleltetéssel.
Szabályzatok dinamikus kiválasztása
A kiterjesztési metódusok például AddPolicyHandler Polly alapú kezelők hozzáadására szolgálnak. A következő AddPolicyHandler túlterhelési metódus (vagy függvény) vizsgálja meg a kérelmet annak eldöntésére, hogy melyik szabályzatot alkalmazza.
var timeout = Policy.TimeoutAsync<HttpResponseMessage>(
TimeSpan.FromSeconds(10));
var longTimeout = Policy.TimeoutAsync<HttpResponseMessage>(
TimeSpan.FromSeconds(30));
services.AddHttpClient("conditionalpolicy")
// Run some code to select a policy based on the request
.AddPolicyHandler(request =>
request.Method == HttpMethod.Get ? timeout : longTimeout);
Az előző kódban, ha a kimenő kérés HTTP GET, a rendszer 10 másodperces időtúllépést alkalmaz. Bármely más HTTP-metódus esetében 30 másodperces időtúllépést használunk.
Több Polly-kezelő hozzáadása
Gyakori a Polly-szabályok beágyazása.
services.AddHttpClient("multiplepolicies")
.AddTransientHttpErrorPolicy(p => p.RetryAsync(3))
.AddTransientHttpErrorPolicy(
p => p.CircuitBreakerAsync(5, TimeSpan.FromSeconds(30)));
Az előző példában:
- A rendszer két kezelőt ad hozzá.
- Az első kezelő AddTransientHttpErrorPolicy segítségével ad hozzá egy újrapróbálkozási szabályzatot. A sikertelen kérelmeket a rendszer akár háromszor is újrapróbálkozza.
- A második
AddTransientHttpErrorPolicyhívás egy áramkör-megszakító házirendet ad hozzá. További külső kérések 30 másodpercig le lesznek tiltva, ha 5 sikertelen kísérlet egymás után történik. Az áramkör-megszakító házirendjei állapotalapúak. Az ügyfélen keresztüli összes hívás ugyanazt az áramkör állapotot osztja meg.
Szabályzatok hozzáadása a Polly-beállításjegyzékből
A rendszeresen használt szabályzatok kezelésének egyik módszere az, hogy egyszeri definiálásuk után regisztrálja azokat egy PolicyRegistry.
A következő kódban:
- A "normál" és a "hosszú" szabályzat hozzáadásra került.
- AddPolicyHandlerFromRegistry hozzáadja a "normál" és a "hosszú" szabályzatokat a beállításjegyzékhez.
public void ConfigureServices(IServiceCollection services)
{
var timeout = Policy.TimeoutAsync<HttpResponseMessage>(
TimeSpan.FromSeconds(10));
var longTimeout = Policy.TimeoutAsync<HttpResponseMessage>(
TimeSpan.FromSeconds(30));
var registry = services.AddPolicyRegistry();
registry.Add("regular", timeout);
registry.Add("long", longTimeout);
services.AddHttpClient("regularTimeoutHandler")
.AddPolicyHandlerFromRegistry("regular");
services.AddHttpClient("longTimeoutHandler")
.AddPolicyHandlerFromRegistry("long");
// Remaining code deleted for brevity.
További információért a IHttpClientFactory és a Polly-integrációkról, lásd a Polly wiki oldalt.
HttpClient és élettartam-kezelése
Minden alkalommal egy új HttpClient példányt ad vissza, amikor a CreateClient-n meghívják a IHttpClientFactory-t. Nevesített ügyfelenként jön létre egy HttpMessageHandler. A gyár kezeli az HttpMessageHandler példányok élettartamát.
IHttpClientFactory összegyűjti a gyár által létrehozott HttpMessageHandler példányokat az erőforrás-felhasználás csökkentése érdekében. A HttpMessageHandler példányok újra felhasználhatók a készletből egy új HttpClient példány létrehozásakor, ha az élettartama még nem járt le.
A kezelők készletezése kívánatos, mivel az egyes kezelők általában saját mögöttes HTTP-kapcsolatokat kezelnek. Ha a szükségesnél több kezelőt hoz létre, az a kapcsolat késéséhez vezethet. Egyes kezelők emellett határozatlan ideig nyitva tartják a kapcsolatokat, ami megakadályozhatja, hogy a kezelő reagáljon a DNS (tartománynévrendszer) változásaira.
Az alapértelmezett kezelő élettartama két perc. Az alapértelmezett érték felülírható nevesített ügyfél alapján:
public void ConfigureServices(IServiceCollection services)
{
services.AddHttpClient("extendedhandlerlifetime")
.SetHandlerLifetime(TimeSpan.FromMinutes(5));
// Remaining code deleted for brevity.
HttpClient a példányok általában olyan .NET-objektumokként kezelhetők, amelyek nem igényelnek ártalmatlanítást. A felszabadítás megszakítja a kimenő kérelmeket, és garantálja, hogy az adott HttpClient példány nem használható a hívás után Dispose.
IHttpClientFactory nyomon követi és megsemmisíti a HttpClient példányok által használt erőforrásokat.
Egyetlen HttpClient példány hosszú ideig történő életben tartása IHttpClientFactory bevezetése előtti gyakori minta. Ez a minta szükségtelenné válik az IHttpClientFactory rendszerre történő migrálás után.
Az IHttpClientFactory alternatívái
A DI-kompatibilis alkalmazások használata IHttpClientFactory elkerüli a következőt:
- Erőforrás-kimerülési problémák az
HttpMessageHandlerpéldányok összevonásával. - Régi DNS-problémákat orvosolhatunk az
HttpMessageHandlerpéldányok rendszeres időközönkénti újraindításával.
Az előző problémákat többféleképpen is meg lehet oldani egy hosszú élettartamú SocketsHttpHandler példány használatával.
- Hozzon létre egy
SocketsHttpHandlerpéldányt, amikor az alkalmazás elindul, és használja azt az alkalmazás teljes élettartama alatt. - Konfiguráljon PooledConnectionLifetime egy megfelelő értékre a DNS frissítési ideje alapján.
- Hozzon létre
HttpClientpéldányokatnew HttpClient(handler, disposeHandler: false)szükség szerint.
Az előző megközelítések hasonló módon oldják meg azokat az erőforrás-kezelési problémákat, amelyeket a IHttpClientFactory megold.
- A
SocketsHttpHandlermegosztja a kapcsolatokat aHttpClientpéldányok között. Ez a megosztás megakadályozza a foglalatok kimerülését. - A
SocketsHttpHandlera kapcsolatokatPooledConnectionLifetimeszerint ciklusokba rendezi az elavult DNS-problémák elkerülése érdekében.
Cookies
A készletezett HttpMessageHandler példányoknál CookieContainer objektumok megosztása történik. A nem várt CookieContainer objektummegosztás gyakran helytelen kódot eredményez. A cookie-kat igénylő alkalmazások esetében fontolja meg az alábbiakat:
- Az automatikus cookie kezelés letiltása
- Elkerülve
IHttpClientFactory
Hívás ConfigurePrimaryHttpMessageHandler az automatikus cookie kezelés letiltására:
services.AddHttpClient("configured-disable-automatic-cookies")
.ConfigurePrimaryHttpMessageHandler(() =>
{
return new HttpClientHandler()
{
UseCookies = false,
};
});
Logging
Az ügyfelek, akik a IHttpClientFactory segítségével lettek létrehozva, naplóüzeneteket rögzítenek az összes kéréshez. A naplózási konfigurációban engedélyezze a megfelelő információs szintet az alapértelmezett naplóüzenetek megtekintéséhez. A további naplózás, például a kérelemfejlécek naplózása csak nyomkövetési szinten szerepel.
Az egyes ügyfelekhez használt naplókategória tartalmazza az ügyfél nevét. Egy MyNamedClient nevű ügyfél például naplózza a "System.Net.Http.HttpClient" kategóriával rendelkező üzeneteket. MyNamedClient. LogicalHandler". A LogicalHandlerrel utótaggal ellátott üzenetek a kérelemkezelő folyamaton kívülre kerülnek. A kéréskor a rendszer az üzeneteket naplózza, mielőtt a folyamat többi kezelője feldolgozta volna. A válaszban az üzenetek naplózva lesznek, miután bármely más folyamatkezelő megkapta a választ.
A naplózás a kérelemkezelő folyamaton belül is megtörténik. A MyNamedClient példában ezek az üzenetek a "System.Net.Http.HttpClient" naplókategória szerint vannak naplózva. MyNamedClient. ClientHandler". A kérés esetében ez az összes többi kezelő lefutása után, és közvetlenül a kérés elküldése előtt fordul elő. A válaszban ez a naplózás a válasz állapotát is tartalmazza, mielőtt az áthalad a kezelőfolyamaton.
A folyamaton kívüli és a folyamaton belüli naplózás engedélyezése lehetővé teszi a többi folyamatkezelő által végrehajtott módosítások ellenőrzését. Ez a kérelemfejlécek vagy a válaszállapot-kód módosításait is tartalmazhatja.
Az ügyfél nevének beleszámításával a naplókategória lehetővé teszi a naplószűrést adott nevesített ügyfelek esetében.
A HttpMessageHandler konfigurálása
Szükség lehet az ügyfél által használt belső HttpMessageHandler konfiguráció szabályozására.
A rendszer névvel ellátott vagy beírt ügyfelek hozzáadásakor ad vissza egy IHttpClientBuilder hibát. A ConfigurePrimaryHttpMessageHandler bővítménymetódus használható meghatalmazott definiálására. A meghatalmazott az ügyfél által használt elsődleges HttpMessageHandler kiszolgáló létrehozásához és konfigurálásához használható:
public void ConfigureServices(IServiceCollection services)
{
services.AddHttpClient("configured-inner-handler")
.ConfigurePrimaryHttpMessageHandler(() =>
{
return new HttpClientHandler()
{
AllowAutoRedirect = false,
UseDefaultCredentials = true
};
});
// Remaining code deleted for brevity.
Az IHttpClientFactory használata konzolalkalmazásban
Egy konzolalkalmazásban adja hozzá a következő csomaghivatkozásokat a projekthez:
Az alábbi példában:
- IHttpClientFactory regisztrálva van a Generic Host szolgáltatáskonténerében.
-
MyServicelétrehoz egy ügyfél-előállító példányt a szolgáltatás alapján, amelyet egyHttpClientlétrehozásához használnak.HttpClientweblap lekérésére szolgál. -
Mainlétrehoz egy hatókört a szolgáltatás metódusánakGetPagevégrehajtásához, és írja a weblap tartalmának első 500 karakterét a konzolra.
using System;
using System.Net.Http;
using System.Threading.Tasks;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging;
class Program
{
static async Task<int> Main(string[] args)
{
var builder = new HostBuilder()
.ConfigureServices((hostContext, services) =>
{
services.AddHttpClient();
services.AddTransient<IMyService, MyService>();
}).UseConsoleLifetime();
var host = builder.Build();
try
{
var myService = host.Services.GetRequiredService<IMyService>();
var pageContent = await myService.GetPage();
Console.WriteLine(pageContent.Substring(0, 500));
}
catch (Exception ex)
{
var logger = host.Services.GetRequiredService<ILogger<Program>>();
logger.LogError(ex, "An error occurred.");
}
return 0;
}
public interface IMyService
{
Task<string> GetPage();
}
public class MyService : IMyService
{
private readonly IHttpClientFactory _clientFactory;
public MyService(IHttpClientFactory clientFactory)
{
_clientFactory = clientFactory;
}
public async Task<string> GetPage()
{
// Content from BBC One: Dr. Who website (©BBC)
var request = new HttpRequestMessage(HttpMethod.Get,
"https://www.bbc.co.uk/programmes/b006q2x0");
var client = _clientFactory.CreateClient();
var response = await client.SendAsync(request);
if (response.IsSuccessStatusCode)
{
return await response.Content.ReadAsStringAsync();
}
else
{
return $"StatusCode: {response.StatusCode}";
}
}
}
}
Élőfej propagálása köztes szoftver
A fejlécpropagálás egy ASP.NET Core köztes szoftver, amely a HTTP-fejléceket propagálja a bejövő kérésből a kimenő HTTP-ügyfélkérelmekbe. A fejlécpropagálás használata:
Hivatkozzon a Microsoft.AspNetCore.HeaderPropagation csomagra .
Konfigurálja a köztes szoftvert és
HttpClienta(z)Startupsorban.public void ConfigureServices(IServiceCollection services) { services.AddControllers(); services.AddHttpClient("MyForwardingClient").AddHeaderPropagation(); services.AddHeaderPropagation(options => { options.Headers.Add("X-TraceId"); }); } public void Configure(IApplicationBuilder app, IWebHostEnvironment env) { if (env.IsDevelopment()) { app.UseDeveloperExceptionPage(); } app.UseHttpsRedirection(); app.UseHeaderPropagation(); app.UseRouting(); app.UseAuthorization(); app.UseEndpoints(endpoints => { endpoints.MapControllers(); }); }Az ügyfél tartalmazza a konfigurált fejléceket a kimenő kérelmekhez:
var client = clientFactory.CreateClient("MyForwardingClient"); var response = client.GetAsync(...);
További erőforrások
Kirk Larkin, Steve Gordon, Glenn Condron és Ryan Nowak.
Egy IHttpClientFactory regisztrálható és használható HttpClient példányok konfigurálására és létrehozására egy alkalmazásban.
IHttpClientFactory a következő előnyöket kínálja:
- Központi helyet biztosít a logikai
HttpClient-példányok elnevezéséhez és konfigurálásához. Például egy github nevű ügyfél regisztrálható és konfigurálható a GitHub eléréséhez. Az alapértelmezett ügyfél regisztrálható az általános hozzáféréshez. - Kodifikálja a kimenő köztes szoftver fogalmát a
HttpClientdelegáló kezelők használatával. Bővítményeket biztosít a Polly-alapú köztes szoftverhez, hogy kihasználhassa a kezelők delegálásának előnyeit aHttpClient. - A mögöttes
HttpClientMessageHandlerpéldányok készletezését és élettartamát kezeli. Az automatikus felügyelet elkerüli az élettartamok manuális kezelésekorHttpClientelőforduló gyakori DNS-(tartománynévrendszer-) problémákat. - Konfigurálható naplózási felületet (via
ILogger) ad hozzá a gyár által létrehozott ügyfeleken keresztül küldött összes kéréshez.
Mintakód megtekintése vagy letöltése (hogyan töltsük le).
A jelen témakör verziójának mintakódja a HTTP-válaszokban visszaadott JSON-tartalom deszerializálására szolgál System.Text.Json . Azoknál a mintáknál, amelyek Json.NET és ReadAsAsync<T>-et használnak, a verzióválasztóval válassza ki ennek a témakörnek a 2.x verzióját.
Használati minták
Az alkalmazásokban többféleképpen IHttpClientFactory is használható:
A legjobb módszer az alkalmazás követelményeitől függ.
Alapszintű használat
IHttpClientFactory a következő hívással AddHttpClientregisztrálható:
public class Startup
{
public Startup(IConfiguration configuration)
{
Configuration = configuration;
}
public IConfiguration Configuration { get; }
public void ConfigureServices(IServiceCollection services)
{
services.AddHttpClient();
// Remaining code deleted for brevity.
Egy IHttpClientFactory kérhető függőséginjektálással (DI). A következő kód IHttpClientFactory-t használ egy HttpClient példány létrehozásához.
public class BasicUsageModel : PageModel
{
private readonly IHttpClientFactory _clientFactory;
public IEnumerable<GitHubBranch> Branches { get; private set; }
public bool GetBranchesError { get; private set; }
public BasicUsageModel(IHttpClientFactory clientFactory)
{
_clientFactory = clientFactory;
}
public async Task OnGet()
{
var request = new HttpRequestMessage(HttpMethod.Get,
"https://api.github.com/repos/dotnet/AspNetCore.Docs/branches");
request.Headers.Add("Accept", "application/vnd.github.v3+json");
request.Headers.Add("User-Agent", "HttpClientFactory-Sample");
var client = _clientFactory.CreateClient();
var response = await client.SendAsync(request);
if (response.IsSuccessStatusCode)
{
using var responseStream = await response.Content.ReadAsStreamAsync();
Branches = await JsonSerializer.DeserializeAsync
<IEnumerable<GitHubBranch>>(responseStream);
}
else
{
GetBranchesError = true;
Branches = Array.Empty<GitHubBranch>();
}
}
}
Az előző példához hasonló használat IHttpClientFactory jó módszer egy meglévő alkalmazás újrabontására. Nincs hatással a használat módjára HttpClient . Azokon a helyeken, ahol HttpClient példányok jönnek létre egy meglévő alkalmazásban, cserélje le ezeket az előfordulásokat CreateClient hívásokkal.
Névvel ellátott ügyfelek
A nevesített ügyfelek akkor jó választásnak számítanak, ha:
- Az alkalmazásnak számos különböző módja van
HttpClienthasználatára. - Sok
HttpClientmás konfigurációval rendelkezik.
Egy megnevezett HttpClient konfigurációja meghatározható a következő helyen, regisztráció során: Startup.ConfigureServices.
services.AddHttpClient("github", c =>
{
c.BaseAddress = new Uri("https://api.github.com/");
// Github API versioning
c.DefaultRequestHeaders.Add("Accept", "application/vnd.github.v3+json");
// Github requires a user-agent
c.DefaultRequestHeaders.Add("User-Agent", "HttpClientFactory-Sample");
});
Az előző kódban az ügyfél a következőkkel van konfigurálva:
- Az alapcím
https://api.github.com/. - A GitHub API használatához két fejléc szükséges.
CreateClient
Minden alkalommal, amikor CreateClient hívásra kerül:
- Létrejön egy
HttpClientúj példány. - A rendszer meghívja a konfigurációs műveletet.
Névvel ellátott ügyfél létrehozásához adja át az ügyfél nevét a következőbe CreateClient:
public class NamedClientModel : PageModel
{
private readonly IHttpClientFactory _clientFactory;
public IEnumerable<GitHubPullRequest> PullRequests { get; private set; }
public bool GetPullRequestsError { get; private set; }
public bool HasPullRequests => PullRequests.Any();
public NamedClientModel(IHttpClientFactory clientFactory)
{
_clientFactory = clientFactory;
}
public async Task OnGet()
{
var request = new HttpRequestMessage(HttpMethod.Get,
"repos/dotnet/AspNetCore.Docs/pulls");
var client = _clientFactory.CreateClient("github");
var response = await client.SendAsync(request);
if (response.IsSuccessStatusCode)
{
using var responseStream = await response.Content.ReadAsStreamAsync();
PullRequests = await JsonSerializer.DeserializeAsync
<IEnumerable<GitHubPullRequest>>(responseStream);
}
else
{
GetPullRequestsError = true;
PullRequests = Array.Empty<GitHubPullRequest>();
}
}
}
Az előző kódban a kérésnek nem kell állomásnevet megadnia. A kód csak az elérési utat tudja átadni, mivel a rendszer az ügyfélhez konfigurált alapcímet használja.
Beírt ügyfelek
Beírt ügyfelek:
- A névvel ellátott ügyfelekkel azonos képességeket biztosíthat anélkül, hogy sztringeket kellene használnia kulcsként.
- Az IntelliSense és a fordító segítséget nyújtanak a kliensek használata során.
- Adjon meg egyetlen helyet egy adott
HttpClienthely konfigurálásához és használatához. Például használható egyetlen gépelt ügyfél:- Egyetlen háttérvégpont esetén.
- A végponttal kapcsolatos összes logika beágyazása.
- Együttműködhet a DI-vel, és szükség esetén injektálható az alkalmazásban.
A gépelt ügyfél egy HttpClient paramétert fogad el a konstruktorában.
public class GitHubService
{
public HttpClient Client { get; }
public GitHubService(HttpClient client)
{
client.BaseAddress = new Uri("https://api.github.com/");
// GitHub API versioning
client.DefaultRequestHeaders.Add("Accept",
"application/vnd.github.v3+json");
// GitHub requires a user-agent
client.DefaultRequestHeaders.Add("User-Agent",
"HttpClientFactory-Sample");
Client = client;
}
public async Task<IEnumerable<GitHubIssue>> GetAspNetDocsIssues()
{
var response = await Client.GetAsync(
"/repos/dotnet/AspNetCore.Docs/issues?state=open&sort=created&direction=desc");
response.EnsureSuccessStatusCode();
using var responseStream = await response.Content.ReadAsStreamAsync();
return await JsonSerializer.DeserializeAsync
<IEnumerable<GitHubIssue>>(responseStream);
}
}
Ha szeretné, hogy a kódkommentárok angolon kívül más nyelvekre is le legyenek fordítva, jelezze nekünk a GitHub vitafórumkérdésénél.
Az előző kódban:
- A konfiguráció át lesz helyezve a beírt ügyfélbe.
- Az
HttpClientobjektum nyilvános tulajdonságként van közzétéve.
Olyan API-specifikus metódusok hozhatók létre, amelyek elérhetővé HttpClient teszik a funkciókat. Az GetAspNetDocsIssues például kódot ágyaz be a nyitott problémák lekéréséhez.
A következő kód meghívja a AddHttpClient a/t Startup.ConfigureServices-ben/-ban egy típusos ügyfélosztály regisztrálására:
services.AddHttpClient<GitHubService>();
A beírt ügyfél átmenetiként van regisztrálva a DI-ben. Az előző kódban AddHttpClient átmeneti szolgáltatásként regisztrál GitHubService . Ez a regisztráció egy gyári módszert használ a következő célokra:
- Hozza létre a
HttpClientegy példányát. - Hozzon létre egy
GitHubServicepéldányt, amelynek konstruktorába adja át aHttpClientpéldányt.
A beírt ügyfél közvetlenül injektálható és felhasználható:
public class TypedClientModel : PageModel
{
private readonly GitHubService _gitHubService;
public IEnumerable<GitHubIssue> LatestIssues { get; private set; }
public bool HasIssue => LatestIssues.Any();
public bool GetIssuesError { get; private set; }
public TypedClientModel(GitHubService gitHubService)
{
_gitHubService = gitHubService;
}
public async Task OnGet()
{
try
{
LatestIssues = await _gitHubService.GetAspNetDocsIssues();
}
catch(HttpRequestException)
{
GetIssuesError = true;
LatestIssues = Array.Empty<GitHubIssue>();
}
}
}
A típusos kliens konfigurációja a regisztráció Startup.ConfigureServices során adható meg, nem pedig a típusos kliens konstruktorában.
services.AddHttpClient<RepoService>(c =>
{
c.BaseAddress = new Uri("https://api.github.com/");
c.DefaultRequestHeaders.Add("Accept", "application/vnd.github.v3+json");
c.DefaultRequestHeaders.Add("User-Agent", "HttpClientFactory-Sample");
});
A HttpClient típusos kliensben beágyazható. Ahelyett, hogy tulajdonságként felfedte volna, definiáljon egy metódust, amely belsőleg hívja meg a HttpClient példányt:
public class RepoService
{
// _httpClient isn't exposed publicly
private readonly HttpClient _httpClient;
public RepoService(HttpClient client)
{
_httpClient = client;
}
public async Task<IEnumerable<string>> GetRepos()
{
var response = await _httpClient.GetAsync("aspnet/repos");
response.EnsureSuccessStatusCode();
using var responseStream = await response.Content.ReadAsStreamAsync();
return await JsonSerializer.DeserializeAsync
<IEnumerable<string>>(responseStream);
}
}
Az előző kódban a rendszer egy privát mezőben tárolja az HttpClient adatokat. A hozzáférés a HttpClient nyilvános GetRepos módszer szerint történik.
Létrehozott ügyfelek
IHttpClientFactory külső kódtárakkal, például a Refittel együtt használható. A Refit egy REST .NET-kódtár. Az API-kat élő felületekké alakítja REST . Az interfész implementációját a RestService dinamikusan hozza létre, miközben a HttpClient külső HTTP-hívások végrehajtására szolgál.
Egy felület és egy válasz definiálva van, amely a külső API-t és annak válaszát jelöli:
public interface IHelloClient
{
[Get("/helloworld")]
Task<Reply> GetMessageAsync();
}
public class Reply
{
public string Message { get; set; }
}
Egy beírt ügyfél hozzáadható a Refit használatával a megvalósítás létrehozásához:
public void ConfigureServices(IServiceCollection services)
{
services.AddHttpClient("hello", c =>
{
c.BaseAddress = new Uri("http://localhost:5000");
})
.AddTypedClient(c => Refit.RestService.For<IHelloClient>(c));
services.AddControllers();
}
A definiált felület szükség esetén felhasználható a DI és a Refit által biztosított implementációval:
[ApiController]
public class ValuesController : ControllerBase
{
private readonly IHelloClient _client;
public ValuesController(IHelloClient client)
{
_client = client;
}
[HttpGet("/")]
public async Task<ActionResult<Reply>> Index()
{
return await _client.GetMessageAsync();
}
}
POST, PUT és DELETE kérések létrehozása
Az előző példákban minden HTTP-kérés a GET HTTP parancsot használja.
HttpClient egyéb HTTP-parancsokat is támogat, többek között a következőket:
- POST
- PUT
- DELETE
- PATCH
A támogatott HTTP-parancsok teljes listáját lásd HttpMethod: .
Az alábbi példa bemutatja, hogyan lehet HTTP POST-kérelmet küldeni:
public async Task CreateItemAsync(TodoItem todoItem)
{
var todoItemJson = new StringContent(
JsonSerializer.Serialize(todoItem, _jsonSerializerOptions),
Encoding.UTF8,
"application/json");
using var httpResponse =
await _httpClient.PostAsync("/api/TodoItems", todoItemJson);
httpResponse.EnsureSuccessStatusCode();
}
Az előző kódban a CreateItemAsync metódus:
- Szerializálja a
TodoItemparamétert JSON formátumba, aSystem.Text.Jsonhasználatával. A szerializálási folyamat konfigurálásához a JsonSerializerOptions egy példányát használja. - Létrehoz egy példányt StringContent a szerializált JSON becsomagolásához a HTTP-kérés törzsébe való küldéshez.
- A JSON-tartalomnak a megadott URL-címre való elküldésére irányuló hívások PostAsync . Ez egy relatív URL-cím, amely hozzáadódik a HttpClient.BaseAddresshez.
- Felhívja EnsureSuccessStatusCode-t, hogy kivételt váltson ki, ha a válasz állapotkódja nem jelzi a sikert.
HttpClient más típusú tartalmakat is támogat. Például: MultipartContent és StreamContent. A támogatott tartalmak teljes listáját lásd HttpContent: .
Az alábbi példa egy HTTP PUT-kérést mutat be:
public async Task SaveItemAsync(TodoItem todoItem)
{
var todoItemJson = new StringContent(
JsonSerializer.Serialize(todoItem),
Encoding.UTF8,
"application/json");
using var httpResponse =
await _httpClient.PutAsync($"/api/TodoItems/{todoItem.Id}", todoItemJson);
httpResponse.EnsureSuccessStatusCode();
}
Az előző kód nagyon hasonlít a POST-példához. A SaveItemAsync metódus a PutAsync-t hívja, nem pedig a PostAsync-t.
Az alábbi példa egy HTTP DELETE-kérést mutat be:
public async Task DeleteItemAsync(long itemId)
{
using var httpResponse =
await _httpClient.DeleteAsync($"/api/TodoItems/{itemId}");
httpResponse.EnsureSuccessStatusCode();
}
Az előző kódban a DeleteItemAsync metódus meghívja a DeleteAsync metódust. Mivel a HTTP DELETE-kérelmek általában nem tartalmaznak törzset, a DeleteAsync metódus nem biztosít olyan túlterhelést, amely elfogad egy HttpContent példányt.
Ha többet szeretne megtudni a különböző HTTP-parancsok a HttpClient használatáról, látogasson el a(z) HttpClient oldalra.
Kimenő kérelem köztes szoftvere
HttpClient a kimenő HTTP-kérésekhez összekapcsolható kezelők delegálásának koncepciója.
IHttpClientFactory:
- Leegyszerűsíti az egyes elnevezett ügyfelekre alkalmazni kívánt kezelők meghatározását.
- Támogatja a több kezelő regisztrációját és láncolását egy kimenő kérelem köztesszoftver-folyamat létrehozásához. Ezek a kezelők a kimenő kérés előtt és után is el tudják végezni a munkát. Ez a minta:
- Hasonló az ASP.NET Core bejövő middleware-folyamatához.
- Mechanizmust biztosít a HTTP-kérelmekkel kapcsolatos horizontális problémák kezelésére, például:
- gyorsítótárazás
- hibakezelés
- szerializálás
- naplózás
Delegáló kezelő létrehozása:
- Származtasson innen: DelegatingHandler.
- Felülírás SendAsync. Hajtsa végre a kódot, mielőtt átadja a kérést a folyamat következő kezelőjének:
public class ValidateHeaderHandler : DelegatingHandler
{
protected override async Task<HttpResponseMessage> SendAsync(
HttpRequestMessage request,
CancellationToken cancellationToken)
{
if (!request.Headers.Contains("X-API-KEY"))
{
return new HttpResponseMessage(HttpStatusCode.BadRequest)
{
Content = new StringContent(
"You must supply an API key header called X-API-KEY")
};
}
return await base.SendAsync(request, cancellationToken);
}
}
Az előző kód ellenőrzi, hogy a X-API-KEY fejléc szerepel-e a kérelemben. Ha X-API-KEY hiányzik, visszatér BadRequest.
Több kezelő is hozzáadható a következővel rendelkező HttpClientkonfigurációhozMicrosoft.Extensions.DependencyInjection.HttpClientBuilderExtensions.AddHttpMessageHandler:
public void ConfigureServices(IServiceCollection services)
{
services.AddTransient<ValidateHeaderHandler>();
services.AddHttpClient("externalservice", c =>
{
// Assume this is an "external" service which requires an API KEY
c.BaseAddress = new Uri("https://localhost:5001/");
})
.AddHttpMessageHandler<ValidateHeaderHandler>();
// Remaining code deleted for brevity.
Az előző kódban a ValidateHeaderHandler be van regisztrálva a DI-hez. A regisztráció után a AddHttpMessageHandler meghívható úgy, hogy megadjuk a kezelő típusát.
Több kezelő is regisztrálható abban a sorrendben, amelyet végre kell hajtaniuk. Minden kezelő burkolja a következő kezelőt, amíg végül a HttpClientHandler végrehajtja a kérést.
services.AddTransient<SecureRequestHandler>();
services.AddTransient<RequestDataHandler>();
services.AddHttpClient("clientwithhandlers")
// This handler is on the outside and called first during the
// request, last during the response.
.AddHttpMessageHandler<SecureRequestHandler>()
// This handler is on the inside, closest to the request being
// sent.
.AddHttpMessageHandler<RequestDataHandler>();
A kimenő kérelem-middleware-ben használd a DI-t
Új delegálási kezelő létrehozásakor IHttpClientFactory a kezelő konstruktorparamétereinek teljesítéséhez a DI-t használja.
IHttpClientFactory
külön DI-hatókört hoz létre az egyes kezelők számára, ami meglepő viselkedéshez vezethet, ha egy kezelő egy hatókörön belüli szolgáltatást használ.
Vegyük például a következő felületet és annak implementációját, amely egy feladatot egy azonosítóval rendelkező műveletként jelöl: OperationId
public interface IOperationScoped
{
string OperationId { get; }
}
public class OperationScoped : IOperationScoped
{
public string OperationId { get; } = Guid.NewGuid().ToString()[^4..];
}
Ahogy a neve is sugallja, IOperationScoped egy hatókörön belüli élettartammal van regisztrálva a DI-ben :
public void ConfigureServices(IServiceCollection services)
{
services.AddDbContext<TodoContext>(options =>
options.UseInMemoryDatabase("TodoItems"));
services.AddHttpContextAccessor();
services.AddHttpClient<TodoClient>((sp, httpClient) =>
{
var httpRequest = sp.GetRequiredService<IHttpContextAccessor>().HttpContext.Request;
// For sample purposes, assume TodoClient is used in the context of an incoming request.
httpClient.BaseAddress = new Uri(UriHelper.BuildAbsolute(httpRequest.Scheme,
httpRequest.Host, httpRequest.PathBase));
httpClient.Timeout = TimeSpan.FromSeconds(5);
});
services.AddScoped<IOperationScoped, OperationScoped>();
services.AddTransient<OperationHandler>();
services.AddTransient<OperationResponseHandler>();
services.AddHttpClient("Operation")
.AddHttpMessageHandler<OperationHandler>()
.AddHttpMessageHandler<OperationResponseHandler>()
.SetHandlerLifetime(TimeSpan.FromSeconds(5));
services.AddControllers();
services.AddRazorPages();
}
A következő delegáló kezelő felhasználja IOperationScoped az X-OPERATION-ID fejléc beállításához a kimenő kérésnél.
public class OperationHandler : DelegatingHandler
{
private readonly IOperationScoped _operationService;
public OperationHandler(IOperationScoped operationScoped)
{
_operationService = operationScoped;
}
protected async override Task<HttpResponseMessage> SendAsync(
HttpRequestMessage request, CancellationToken cancellationToken)
{
request.Headers.Add("X-OPERATION-ID", _operationService.OperationId);
return await base.SendAsync(request, cancellationToken);
}
}
HttpRequestsSample A letöltésben keresse meg /Operation és frissítse a lapot. A kérelem hatókörének értéke az egyes kérések esetében módosul, de a kezelő hatókörének értéke csak 5 másodpercenként változik.
A kezelők bármilyen hatókörű szolgáltatástól függhetnek. Azok a szolgáltatások, amelyektől a kezelők függenek, a kezelő ártalmatlanításakor lesznek megsemmisítve.
A kérésenkénti állapotok üzenetkezelőkkel való megosztásához használja az alábbi módszerek egyikét:
- Az adatokat a kezelőbe a HttpRequestMessage.Properties használatával továbbítsa.
- Az aktuális kérés eléréséhez használható IHttpContextAccessor .
- Hozzon létre egy egyéni AsyncLocal<T> tárolóobjektumot az adatok továbbításához.
Polly-alapú kezelők használata
IHttpClientFactory integrálható a harmadik féltől származó Polly könyvtárral. A Polly egy átfogó rugalmassági és átmeneti hibakezelési kódtár a .NET-hez. Lehetővé teszi, hogy a fejlesztők folyékonyan és szálbiztosan fejezzék ki az olyan szabályzatokat, mint az Újrapróbálkozás, a Megszakító, az Időtúllépés, a Válaszfal elkülönítése és a Fallback.
A bővítménymetelyek lehetővé teszik a Polly-szabályzatok használatát konfigurált HttpClient példányokkal. A Polly-bővítmények támogatják a Polly-alapú kezelők ügyfelekhez való hozzáadását. A Pollyhoz a Microsoft.Extensions.Http.Polly NuGet csomag szükséges.
Átmeneti hibák kezelése
A hibák általában akkor fordulnak elő, ha a külső HTTP-hívások átmenetiek.
AddTransientHttpErrorPolicy lehetővé teszi, hogy egy szabályzat definiálva legyen az átmeneti hibák kezelésére. A következő válaszok kezelésére konfigurált AddTransientHttpErrorPolicy szabályzatok:
- HttpRequestException
- HTTP 5xx
- HTTP 408
AddTransientHttpErrorPolicy hozzáférést biztosít egy PolicyBuilder olyan objektumhoz, amely egy lehetséges átmeneti hibát jelképező hibák kezelésére van konfigurálva:
public void ConfigureServices(IServiceCollection services)
{
services.AddHttpClient<UnreliableEndpointCallerService>()
.AddTransientHttpErrorPolicy(p =>
p.WaitAndRetryAsync(3, _ => TimeSpan.FromMilliseconds(600)));
// Remaining code deleted for brevity.
Az előző kódban egy WaitAndRetryAsync szabályzat van definiálva. A sikertelen kérelmeket a rendszer akár háromszor is újrapróbálkozza a kísérletek között 600 ms késleltetéssel.
Szabályzatok dinamikus kiválasztása
A kiterjesztési metódusok például AddPolicyHandler Polly alapú kezelők hozzáadására szolgálnak. A következő AddPolicyHandler túlterhelési metódus (vagy függvény) vizsgálja meg a kérelmet annak eldöntésére, hogy melyik szabályzatot alkalmazza.
var timeout = Policy.TimeoutAsync<HttpResponseMessage>(
TimeSpan.FromSeconds(10));
var longTimeout = Policy.TimeoutAsync<HttpResponseMessage>(
TimeSpan.FromSeconds(30));
services.AddHttpClient("conditionalpolicy")
// Run some code to select a policy based on the request
.AddPolicyHandler(request =>
request.Method == HttpMethod.Get ? timeout : longTimeout);
Az előző kódban, ha a kimenő kérés HTTP GET, a rendszer 10 másodperces időtúllépést alkalmaz. Bármely más HTTP-metódus esetében 30 másodperces időtúllépést használunk.
Több Polly-kezelő hozzáadása
Gyakori a Polly-szabályok beágyazása.
services.AddHttpClient("multiplepolicies")
.AddTransientHttpErrorPolicy(p => p.RetryAsync(3))
.AddTransientHttpErrorPolicy(
p => p.CircuitBreakerAsync(5, TimeSpan.FromSeconds(30)));
Az előző példában:
- A rendszer két kezelőt ad hozzá.
- Az első kezelő AddTransientHttpErrorPolicy segítségével ad hozzá egy újrapróbálkozási szabályzatot. A sikertelen kérelmeket a rendszer akár háromszor is újrapróbálkozza.
- A második
AddTransientHttpErrorPolicyhívás egy áramkör-megszakító házirendet ad hozzá. További külső kérések 30 másodpercig le lesznek tiltva, ha 5 sikertelen kísérlet egymás után történik. Az áramkör-megszakító házirendjei állapotalapúak. Az ügyfélen keresztüli összes hívás ugyanazt az áramkör állapotot osztja meg.
Szabályzatok hozzáadása a Polly-beállításjegyzékből
A rendszeresen használt szabályzatok kezelésének egyik módszere az, hogy egyszeri definiálásuk után regisztrálja azokat egy PolicyRegistry.
A következő kódban:
- A "normál" és a "hosszú" szabályzat hozzáadásra került.
- AddPolicyHandlerFromRegistry hozzáadja a "normál" és a "hosszú" szabályzatokat a beállításjegyzékhez.
public void ConfigureServices(IServiceCollection services)
{
var timeout = Policy.TimeoutAsync<HttpResponseMessage>(
TimeSpan.FromSeconds(10));
var longTimeout = Policy.TimeoutAsync<HttpResponseMessage>(
TimeSpan.FromSeconds(30));
var registry = services.AddPolicyRegistry();
registry.Add("regular", timeout);
registry.Add("long", longTimeout);
services.AddHttpClient("regularTimeoutHandler")
.AddPolicyHandlerFromRegistry("regular");
services.AddHttpClient("longTimeoutHandler")
.AddPolicyHandlerFromRegistry("long");
// Remaining code deleted for brevity.
További információért a IHttpClientFactory és a Polly-integrációkról, lásd a Polly wiki oldalt.
HttpClient és élettartam-kezelése
Minden alkalommal egy új HttpClient példányt ad vissza, amikor a CreateClient-n meghívják a IHttpClientFactory-t. Nevesített ügyfelenként jön létre egy HttpMessageHandler. A gyár kezeli az HttpMessageHandler példányok élettartamát.
IHttpClientFactory összegyűjti a gyár által létrehozott HttpMessageHandler példányokat az erőforrás-felhasználás csökkentése érdekében. A HttpMessageHandler példányok újra felhasználhatók a készletből egy új HttpClient példány létrehozásakor, ha az élettartama még nem járt le.
A kezelők készletezése kívánatos, mivel az egyes kezelők általában saját mögöttes HTTP-kapcsolatokat kezelnek. Ha a szükségesnél több kezelőt hoz létre, az a kapcsolat késéséhez vezethet. Egyes kezelők emellett határozatlan ideig nyitva tartják a kapcsolatokat, ami megakadályozhatja, hogy a kezelő reagáljon a DNS (tartománynévrendszer) változásaira.
Az alapértelmezett kezelő élettartama két perc. Az alapértelmezett érték felülírható nevesített ügyfél alapján:
public void ConfigureServices(IServiceCollection services)
{
services.AddHttpClient("extendedhandlerlifetime")
.SetHandlerLifetime(TimeSpan.FromMinutes(5));
// Remaining code deleted for brevity.
HttpClient a példányok általában olyan .NET-objektumokként kezelhetők, amelyek nem igényelnek ártalmatlanítást. A felszabadítás megszakítja a kimenő kérelmeket, és garantálja, hogy az adott HttpClient példány nem használható a hívás után Dispose.
IHttpClientFactory nyomon követi és megsemmisíti a HttpClient példányok által használt erőforrásokat.
Egyetlen HttpClient példány hosszú ideig történő életben tartása IHttpClientFactory bevezetése előtti gyakori minta. Ez a minta szükségtelenné válik az IHttpClientFactory rendszerre történő migrálás után.
Az IHttpClientFactory alternatívái
A DI-kompatibilis alkalmazások használata IHttpClientFactory elkerüli a következőt:
- Erőforrás-kimerülési problémák az
HttpMessageHandlerpéldányok összevonásával. - Régi DNS-problémákat orvosolhatunk az
HttpMessageHandlerpéldányok rendszeres időközönkénti újraindításával.
Az előző problémákat többféleképpen is meg lehet oldani egy hosszú élettartamú SocketsHttpHandler példány használatával.
- Hozzon létre egy
SocketsHttpHandlerpéldányt, amikor az alkalmazás elindul, és használja azt az alkalmazás teljes élettartama alatt. - Konfiguráljon PooledConnectionLifetime egy megfelelő értékre a DNS frissítési ideje alapján.
- Hozzon létre
HttpClientpéldányokatnew HttpClient(handler, disposeHandler: false)szükség szerint.
Az előző megközelítések hasonló módon oldják meg azokat az erőforrás-kezelési problémákat, amelyeket a IHttpClientFactory megold.
- A
SocketsHttpHandlermegosztja a kapcsolatokat aHttpClientpéldányok között. Ez a megosztás megakadályozza a foglalatok kimerülését. - A
SocketsHttpHandlera kapcsolatokatPooledConnectionLifetimeszerint ciklusokba rendezi az elavult DNS-problémák elkerülése érdekében.
Cookies
A készletezett HttpMessageHandler példányoknál CookieContainer objektumok megosztása történik. A nem várt CookieContainer objektummegosztás gyakran helytelen kódot eredményez. A cookie-kat igénylő alkalmazások esetében fontolja meg az alábbiakat:
- Az automatikus cookie kezelés letiltása
- Elkerülve
IHttpClientFactory
Hívás ConfigurePrimaryHttpMessageHandler az automatikus cookie kezelés letiltására:
services.AddHttpClient("configured-disable-automatic-cookies")
.ConfigurePrimaryHttpMessageHandler(() =>
{
return new HttpClientHandler()
{
UseCookies = false,
};
});
Logging
Az ügyfelek, akik a IHttpClientFactory segítségével lettek létrehozva, naplóüzeneteket rögzítenek az összes kéréshez. A naplózási konfigurációban engedélyezze a megfelelő információs szintet az alapértelmezett naplóüzenetek megtekintéséhez. A további naplózás, például a kérelemfejlécek naplózása csak nyomkövetési szinten szerepel.
Az egyes ügyfelekhez használt naplókategória tartalmazza az ügyfél nevét. Egy MyNamedClient nevű ügyfél például naplózza a "System.Net.Http.HttpClient" kategóriával rendelkező üzeneteket. MyNamedClient. LogicalHandler". A LogicalHandlerrel utótaggal ellátott üzenetek a kérelemkezelő folyamaton kívülre kerülnek. A kéréskor a rendszer az üzeneteket naplózza, mielőtt a folyamat többi kezelője feldolgozta volna. A válaszban az üzenetek naplózva lesznek, miután bármely más folyamatkezelő megkapta a választ.
A naplózás a kérelemkezelő folyamaton belül is megtörténik. A MyNamedClient példában ezek az üzenetek a "System.Net.Http.HttpClient" naplókategória szerint vannak naplózva. MyNamedClient. ClientHandler". A kérés esetében ez az összes többi kezelő lefutása után, és közvetlenül a kérés elküldése előtt fordul elő. A válaszban ez a naplózás a válasz állapotát is tartalmazza, mielőtt az áthalad a kezelőfolyamaton.
A folyamaton kívüli és a folyamaton belüli naplózás engedélyezése lehetővé teszi a többi folyamatkezelő által végrehajtott módosítások ellenőrzését. Ez a kérelemfejlécek vagy a válaszállapot-kód módosításait is tartalmazhatja.
Az ügyfél nevének beleszámításával a naplókategória lehetővé teszi a naplószűrést adott nevesített ügyfelek esetében.
A HttpMessageHandler konfigurálása
Szükség lehet az ügyfél által használt belső HttpMessageHandler konfiguráció szabályozására.
A rendszer névvel ellátott vagy beírt ügyfelek hozzáadásakor ad vissza egy IHttpClientBuilder hibát. A ConfigurePrimaryHttpMessageHandler bővítménymetódus használható meghatalmazott definiálására. A meghatalmazott az ügyfél által használt elsődleges HttpMessageHandler kiszolgáló létrehozásához és konfigurálásához használható:
public void ConfigureServices(IServiceCollection services)
{
services.AddHttpClient("configured-inner-handler")
.ConfigurePrimaryHttpMessageHandler(() =>
{
return new HttpClientHandler()
{
AllowAutoRedirect = false,
UseDefaultCredentials = true
};
});
// Remaining code deleted for brevity.
Az IHttpClientFactory használata konzolalkalmazásban
Egy konzolalkalmazásban adja hozzá a következő csomaghivatkozásokat a projekthez:
Az alábbi példában:
- IHttpClientFactory regisztrálva van a Generic Host szolgáltatáskonténerében.
-
MyServicelétrehoz egy ügyfél-előállító példányt a szolgáltatás alapján, amelyet egyHttpClientlétrehozásához használnak.HttpClientweblap lekérésére szolgál. -
Mainlétrehoz egy hatókört a szolgáltatás metódusánakGetPagevégrehajtásához, és írja a weblap tartalmának első 500 karakterét a konzolra.
using System;
using System.Net.Http;
using System.Threading.Tasks;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging;
class Program
{
static async Task<int> Main(string[] args)
{
var builder = new HostBuilder()
.ConfigureServices((hostContext, services) =>
{
services.AddHttpClient();
services.AddTransient<IMyService, MyService>();
}).UseConsoleLifetime();
var host = builder.Build();
try
{
var myService = host.Services.GetRequiredService<IMyService>();
var pageContent = await myService.GetPage();
Console.WriteLine(pageContent.Substring(0, 500));
}
catch (Exception ex)
{
var logger = host.Services.GetRequiredService<ILogger<Program>>();
logger.LogError(ex, "An error occurred.");
}
return 0;
}
public interface IMyService
{
Task<string> GetPage();
}
public class MyService : IMyService
{
private readonly IHttpClientFactory _clientFactory;
public MyService(IHttpClientFactory clientFactory)
{
_clientFactory = clientFactory;
}
public async Task<string> GetPage()
{
// Content from BBC One: Dr. Who website (©BBC)
var request = new HttpRequestMessage(HttpMethod.Get,
"https://www.bbc.co.uk/programmes/b006q2x0");
var client = _clientFactory.CreateClient();
var response = await client.SendAsync(request);
if (response.IsSuccessStatusCode)
{
return await response.Content.ReadAsStringAsync();
}
else
{
return $"StatusCode: {response.StatusCode}";
}
}
}
}
Élőfej propagálása köztes szoftver
A fejlécpropagálás egy ASP.NET Core köztes szoftver, amely a HTTP-fejléceket propagálja a bejövő kérésből a kimenő HTTP-ügyfélkérelmekbe. A fejlécpropagálás használata:
Hivatkozzon a Microsoft.AspNetCore.HeaderPropagation csomagra .
Konfigurálja a köztes szoftvert és
HttpClienta(z)Startupsorban.public void ConfigureServices(IServiceCollection services) { services.AddControllers(); services.AddHttpClient("MyForwardingClient").AddHeaderPropagation(); services.AddHeaderPropagation(options => { options.Headers.Add("X-TraceId"); }); } public void Configure(IApplicationBuilder app, IWebHostEnvironment env) { if (env.IsDevelopment()) { app.UseDeveloperExceptionPage(); } app.UseHttpsRedirection(); app.UseHeaderPropagation(); app.UseRouting(); app.UseAuthorization(); app.UseEndpoints(endpoints => { endpoints.MapControllers(); }); }Az ügyfél tartalmazza a konfigurált fejléceket a kimenő kérelmekhez:
var client = clientFactory.CreateClient("MyForwardingClient"); var response = client.GetAsync(...);
További erőforrások
Glenn Condron, Ryan Nowak és Steve Gordon
Egy IHttpClientFactory regisztrálható és használható HttpClient példányok konfigurálására és létrehozására egy alkalmazásban. A következő előnyöket nyújtja:
- Központi helyet biztosít a logikai
HttpClient-példányok elnevezéséhez és konfigurálásához. Egy GitHub-ügyfél például regisztrálható és konfigurálható a GitHub eléréséhez. Az alapértelmezett ügyfél más célokra is regisztrálható. - Kodifikálja a kimenő köztes szoftver fogalmát a kezelők
HttpClientdelegálásán keresztül, és bővítményeket biztosít a Polly-alapú köztes szoftverhez, hogy kihasználhassa ezt. - Kezeli a mögöttes
HttpClientMessageHandlerpéldányok készletezését és élettartamát, hogy elkerülje azHttpClientélettartamának manuális kezelésekor előforduló gyakori DNS-problémákat. - Konfigurálható naplózási felületet (via
ILogger) ad hozzá a gyár által létrehozott ügyfeleken keresztül küldött összes kéréshez.
Mintakód megtekintése vagy letöltése (hogyan töltsd le)
Prerequisites
A .NET-keretrendszert célzó projektekhez telepíteni kell a Microsoft.Extensions.Http NuGet csomagot. A .NET Core-t célzó és a Microsoft.AspNetCore.App metapackage-ra hivatkozó projektek már tartalmazzák a Microsoft.Extensions.Http csomagot.
Használati minták
Az alkalmazásokban többféleképpen IHttpClientFactory is használható:
Egyik sem szigorúan jobb a másiknál. A legjobb megközelítés az alkalmazás korlátaitól függ.
Alapszintű használat
A IHttpClientFactory regisztrálható úgy, hogy a AddHttpClient metóduson belüli IServiceCollection-ra meghívjuk a Startup.ConfigureServices bővítménymetódust.
services.AddHttpClient();
Regisztráció után a kód bárhol elfogadhat egy IHttpClientFactory-t, ahol szolgáltatásokat lehet injektálni függőséginjektálással (DI).
IHttpClientFactory használható egy HttpClient példány létrehozásához.
public class BasicUsageModel : PageModel
{
private readonly IHttpClientFactory _clientFactory;
public IEnumerable<GitHubBranch> Branches { get; private set; }
public bool GetBranchesError { get; private set; }
public BasicUsageModel(IHttpClientFactory clientFactory)
{
_clientFactory = clientFactory;
}
public async Task OnGet()
{
var request = new HttpRequestMessage(HttpMethod.Get,
"https://api.github.com/repos/dotnet/AspNetCore.Docs/branches");
request.Headers.Add("Accept", "application/vnd.github.v3+json");
request.Headers.Add("User-Agent", "HttpClientFactory-Sample");
var client = _clientFactory.CreateClient();
var response = await client.SendAsync(request);
if (response.IsSuccessStatusCode)
{
Branches = await response.Content
.ReadAsAsync<IEnumerable<GitHubBranch>>();
}
else
{
GetBranchesError = true;
Branches = Array.Empty<GitHubBranch>();
}
}
}
Az ilyen módon történő használat IHttpClientFactory jó módszer egy meglévő alkalmazás átalakítására. Nincs hatással a használat módjára HttpClient . Azokon a helyeken, ahol HttpClient példányokat hoznak létre, cserélje le ezeket az előfordulásokat a CreateClient hívására.
Névvel ellátott ügyfelek
Ha egy alkalmazásnak több, különböző konfigurációval rendelkező, eltérő felhasználásra van szüksége HttpClient, akkor az egyik lehetőség a név szerint megnevezett kliensek használata. A névvel ellátott HttpClient konfiguráció a regisztráció során adható meg a következőben Startup.ConfigureServices: .
services.AddHttpClient("github", c =>
{
c.BaseAddress = new Uri("https://api.github.com/");
// Github API versioning
c.DefaultRequestHeaders.Add("Accept", "application/vnd.github.v3+json");
// Github requires a user-agent
c.DefaultRequestHeaders.Add("User-Agent", "HttpClientFactory-Sample");
});
Az előző kódban a AddHttpClient kerül meghívásra, biztosítva a github nevet. Az ügyfél alapértelmezett konfigurációt alkalmaz, nevezetesen az alapcímet és a GitHub API használatához szükséges két fejlécet.
Minden alkalommal, amikor CreateClient meghívásra kerül, létrejön egy új HttpClient példány, és a konfigurációs műveletet is meghívja.
Ahhoz, hogy használjuk a megadott ügyfelet, egy sztring paramétert adhatunk át a(z) CreateClient számára. Adja meg a létrehozandó ügyfél nevét:
public class NamedClientModel : PageModel
{
private readonly IHttpClientFactory _clientFactory;
public IEnumerable<GitHubPullRequest> PullRequests { get; private set; }
public bool GetPullRequestsError { get; private set; }
public bool HasPullRequests => PullRequests.Any();
public NamedClientModel(IHttpClientFactory clientFactory)
{
_clientFactory = clientFactory;
}
public async Task OnGet()
{
var request = new HttpRequestMessage(HttpMethod.Get,
"repos/dotnet/AspNetCore.Docs/pulls");
var client = _clientFactory.CreateClient("github");
var response = await client.SendAsync(request);
if (response.IsSuccessStatusCode)
{
PullRequests = await response.Content
.ReadAsAsync<IEnumerable<GitHubPullRequest>>();
}
else
{
GetPullRequestsError = true;
PullRequests = Array.Empty<GitHubPullRequest>();
}
}
}
Az előző kódban a kérésnek nem kell állomásnevet megadnia. Csak az elérési utat tudja átadni, mivel a rendszer az ügyfélhez konfigurált alapcímet használja.
Beírt ügyfelek
Beírt ügyfelek:
- A névvel ellátott ügyfelekkel azonos képességeket biztosíthat anélkül, hogy sztringeket kellene használnia kulcsként.
- Az IntelliSense és a fordító segítséget nyújtanak a kliensek használata során.
- Adjon meg egyetlen helyet egy adott
HttpClienthely konfigurálásához és használatához. Például egyetlen beírt ügyfél használható egyetlen háttérvégponthoz, és beágyazhatja az adott végponttal foglalkozó összes logikát. - A DI-vel dolgozhat, és szükség esetén injektálható az alkalmazásába.
A gépelt ügyfél egy HttpClient paramétert fogad el a konstruktorában.
public class GitHubService
{
public HttpClient Client { get; }
public GitHubService(HttpClient client)
{
client.BaseAddress = new Uri("https://api.github.com/");
// GitHub API versioning
client.DefaultRequestHeaders.Add("Accept",
"application/vnd.github.v3+json");
// GitHub requires a user-agent
client.DefaultRequestHeaders.Add("User-Agent",
"HttpClientFactory-Sample");
Client = client;
}
public async Task<IEnumerable<GitHubIssue>> GetAspNetDocsIssues()
{
var response = await Client.GetAsync(
"/repos/dotnet/AspNetCore.Docs/issues?state=open&sort=created&direction=desc");
response.EnsureSuccessStatusCode();
var result = await response.Content
.ReadAsAsync<IEnumerable<GitHubIssue>>();
return result;
}
}
Az előző kódban a konfiguráció át lesz helyezve a beírt ügyfélbe. Az HttpClient objektum nyilvános tulajdonságként van közzétéve. A funkciókat elérhetővé tevő HttpClient API-specifikus metódusok definiálhatók. A GetAspNetDocsIssues metódus beágyazza a GitHub-adattárak legutóbbi nyitott problémáinak lekérdezéséhez és elemzéséhez szükséges kódot.
Tipizált ügyfél regisztrálásához az AddHttpClient általános bővítménymetódus használható a Startup.ConfigureServices tipizált ügyfélosztály megadásával.
services.AddHttpClient<GitHubService>();
A beírt ügyfél átmenetiként van regisztrálva a DI-ben. A beírt ügyfél közvetlenül injektálható és felhasználható:
public class TypedClientModel : PageModel
{
private readonly GitHubService _gitHubService;
public IEnumerable<GitHubIssue> LatestIssues { get; private set; }
public bool HasIssue => LatestIssues.Any();
public bool GetIssuesError { get; private set; }
public TypedClientModel(GitHubService gitHubService)
{
_gitHubService = gitHubService;
}
public async Task OnGet()
{
try
{
LatestIssues = await _gitHubService.GetAspNetDocsIssues();
}
catch(HttpRequestException)
{
GetIssuesError = true;
LatestIssues = Array.Empty<GitHubIssue>();
}
}
}
Ha előnyben részesítik, a típusos ügyfél konfigurációja megadható a regisztráció során Startup.ConfigureServices-ban, nem pedig a típusos ügyfél konstruktorában.
services.AddHttpClient<RepoService>(c =>
{
c.BaseAddress = new Uri("https://api.github.com/");
c.DefaultRequestHeaders.Add("Accept", "application/vnd.github.v3+json");
c.DefaultRequestHeaders.Add("User-Agent", "HttpClientFactory-Sample");
});
A típusos ügyfélbe teljesen beágyazható HttpClient. Ahelyett, hogy tulajdonságként való kitétele történne, nyilvános metódusok is megadhatók, amelyek belsőleg meghívják a HttpClient példányt.
public class RepoService
{
// _httpClient isn't exposed publicly
private readonly HttpClient _httpClient;
public RepoService(HttpClient client)
{
_httpClient = client;
}
public async Task<IEnumerable<string>> GetRepos()
{
var response = await _httpClient.GetAsync("aspnet/repos");
response.EnsureSuccessStatusCode();
var result = await response.Content
.ReadAsAsync<IEnumerable<string>>();
return result;
}
}
Az előző kódban a rendszer privát mezőként tárolja az HttpClient adatokat. A külső hívásokhoz való minden hozzáférés a GetRepos metóduson keresztül történik.
Létrehozott ügyfelek
IHttpClientFactory más külső kódtárakkal, például a Refittel együtt is használható. A Refit egy REST .NET-kódtár. Az API-kat élő felületekké alakítja REST . Az interfész implementációját a RestService dinamikusan hozza létre, miközben a HttpClient külső HTTP-hívások végrehajtására szolgál.
Egy felület és egy válasz definiálva van, amely a külső API-t és annak válaszát jelöli:
public interface IHelloClient
{
[Get("/helloworld")]
Task<Reply> GetMessageAsync();
}
public class Reply
{
public string Message { get; set; }
}
Egy beírt ügyfél hozzáadható a Refit használatával a megvalósítás létrehozásához:
public void ConfigureServices(IServiceCollection services)
{
services.AddHttpClient("hello", c =>
{
c.BaseAddress = new Uri("http://localhost:5000");
})
.AddTypedClient(c => Refit.RestService.For<IHelloClient>(c));
services.AddMvc();
}
A definiált felület szükség esetén felhasználható a DI és a Refit által biztosított implementációval:
[ApiController]
public class ValuesController : ControllerBase
{
private readonly IHelloClient _client;
public ValuesController(IHelloClient client)
{
_client = client;
}
[HttpGet("/")]
public async Task<ActionResult<Reply>> Index()
{
return await _client.GetMessageAsync();
}
}
Kimenő kérelem köztes szoftvere
HttpClient már rendelkezik a kimenő HTTP-kérésekhez összekapcsolható kezelők delegálásának fogalmával. Ez IHttpClientFactory megkönnyíti az egyes nevesített ügyfelekre alkalmazni kívánt kezelők meghatározását. Támogatja a több kezelő regisztrációját és láncolását egy kimenő kérelem köztesszoftver-folyamat létrehozásához. Ezek a kezelők a kimenő kérés előtt és után is el tudják végezni a munkát. Ez a minta hasonló a ASP.NET Core bejövő köztes szoftverfolyamatához. A minta egy mechanizmust biztosít a HTTP-kérelmekkel kapcsolatos horizontális problémák kezelésére, beleértve a gyorsítótárazást, a hibakezelést, a szerializálást és a naplózást.
Kezelő létrehozásához definiáljon egy osztályt, amely a forrásból DelegatingHandlerszármazik. Bírálja felül a SendAsync kódot végrehajtó metódust, mielőtt átadja a kérést a folyamat következő kezelőjének:
public class ValidateHeaderHandler : DelegatingHandler
{
protected override async Task<HttpResponseMessage> SendAsync(
HttpRequestMessage request,
CancellationToken cancellationToken)
{
if (!request.Headers.Contains("X-API-KEY"))
{
return new HttpResponseMessage(HttpStatusCode.BadRequest)
{
Content = new StringContent(
"You must supply an API key header called X-API-KEY")
};
}
return await base.SendAsync(request, cancellationToken);
}
}
Az előző kód egy alapszintű kezelőt határoz meg. Ellenőrzi, hogy szerepel-e X-API-KEY fejléc a kérelemben. Ha a fejléc hiányzik, elkerülheti a HTTP-hívást, és megfelelő választ ad vissza.
A regisztráció során egy vagy több kezelő is hozzáadható a konfigurációhoz.HttpClient Ezt a feladatot kiterjesztési metódusokkal hajtják végre a következőn: IHttpClientBuilder.
services.AddTransient<ValidateHeaderHandler>();
services.AddHttpClient("externalservice", c =>
{
// Assume this is an "external" service which requires an API KEY
c.BaseAddress = new Uri("https://localhost:5000/");
})
.AddHttpMessageHandler<ValidateHeaderHandler>();
Az előző kódban a ValidateHeaderHandler be van regisztrálva a DI-hez. A kezelőt a DI-ben átmeneti szolgáltatásként kell regisztrálni, soha nem hatókörként. Ha a kezelő hatókörrel rendelkező szolgáltatásként van regisztrálva, és a kezelő által igénybe vett szolgáltatások eldobhatók:
- A kezelő szolgáltatásai a kezelő hatókörének kiesése előtt megsemmisíthetők.
- Az elvetett kezelőszolgáltatások miatt a kezelő meghibásodik.
Regisztrálás után a AddHttpMessageHandler meghívható, átadva a kezelő típust.
Több kezelő is regisztrálható abban a sorrendben, amelyet végre kell hajtaniuk. Minden kezelő burkolja a következő kezelőt, amíg végül a HttpClientHandler végrehajtja a kérést.
services.AddTransient<SecureRequestHandler>();
services.AddTransient<RequestDataHandler>();
services.AddHttpClient("clientwithhandlers")
// This handler is on the outside and called first during the
// request, last during the response.
.AddHttpMessageHandler<SecureRequestHandler>()
// This handler is on the inside, closest to the request being
// sent.
.AddHttpMessageHandler<RequestDataHandler>();
A kérésenkénti állapotok üzenetkezelőkkel való megosztásához használja az alábbi módszerek egyikét:
- Az adatokat a kezelőbe a
HttpRequestMessage.Propertieshasználatával továbbítsa. - Az aktuális kérés eléréséhez használható
IHttpContextAccessor. - Hozzon létre egy egyéni
AsyncLocaltárolóobjektumot az adatok továbbításához.
Polly-alapú kezelők használata
IHttpClientFactory integrálható egy népszerű, harmadik féltől származó, Polly nevű könyvtárral. A Polly egy átfogó rugalmassági és átmeneti hibakezelési kódtár a .NET-hez. Lehetővé teszi, hogy a fejlesztők folyékonyan és szálbiztosan fejezzék ki az olyan szabályzatokat, mint az Újrapróbálkozás, a Megszakító, az Időtúllépés, a Válaszfal elkülönítése és a Fallback.
A bővítménymetelyek lehetővé teszik a Polly-szabályzatok használatát konfigurált HttpClient példányokkal. A Polly-bővítmények:
- Polly-alapú kezelők ügyfelekhez való hozzáadásának támogatása.
- A Microsoft.Extensions.Http.Polly NuGet csomag telepítése után használható. A csomag nem szerepel a ASP.NET Core megosztott keretrendszerében.
Átmeneti hibák kezelése
A leggyakoribb hibák akkor fordulnak elő, ha a külső HTTP-hívások átmenetiek. A rendszer egy kényelmes bővítménymetódust is tartalmaz AddTransientHttpErrorPolicy , amely lehetővé teszi, hogy egy szabályzatot definiáljon az átmeneti hibák kezelésére. Az ezzel a bővítménymódszerrel konfigurált szabályzatok kezelik a HttpRequestException, HTTP 5xx válaszokat és HTTP 408 válaszokat.
A AddTransientHttpErrorPolicy bővítmény a Startup.ConfigureServices-en belül használható. A bővítmény hozzáférést biztosít egy PolicyBuilder olyan objektumhoz, amely egy lehetséges átmeneti hibát jelképező hibák kezelésére van konfigurálva:
services.AddHttpClient<UnreliableEndpointCallerService>()
.AddTransientHttpErrorPolicy(p =>
p.WaitAndRetryAsync(3, _ => TimeSpan.FromMilliseconds(600)));
Az előző kódban egy WaitAndRetryAsync szabályzat van definiálva. A sikertelen kérelmeket a rendszer akár háromszor is újrapróbálkozza a kísérletek között 600 ms késleltetéssel.
Szabályzatok dinamikus kiválasztása
További bővítménymetelyek is léteznek, amelyek Polly-alapú kezelők hozzáadására használhatók. Az egyik ilyen kiterjesztés, AddPolicyHandleramely több túlterheléssel rendelkezik. Egy túlterhelés lehetővé teszi a kérés vizsgálatát, amikor meghatározza, hogy melyik szabályzatot alkalmazza:
var timeout = Policy.TimeoutAsync<HttpResponseMessage>(
TimeSpan.FromSeconds(10));
var longTimeout = Policy.TimeoutAsync<HttpResponseMessage>(
TimeSpan.FromSeconds(30));
services.AddHttpClient("conditionalpolicy")
// Run some code to select a policy based on the request
.AddPolicyHandler(request =>
request.Method == HttpMethod.Get ? timeout : longTimeout);
Az előző kódban, ha a kimenő kérés HTTP GET, a rendszer 10 másodperces időtúllépést alkalmaz. Bármely más HTTP-metódus esetében 30 másodperces időtúllépést használunk.
Több Polly-kezelő hozzáadása
Gyakori, hogy a Polly-irányelveket egymásba ágyazzák a továbbfejlesztett funkciók biztosítása érdekében.
services.AddHttpClient("multiplepolicies")
.AddTransientHttpErrorPolicy(p => p.RetryAsync(3))
.AddTransientHttpErrorPolicy(
p => p.CircuitBreakerAsync(5, TimeSpan.FromSeconds(30)));
Az előző példában a rendszer két kezelőt ad hozzá. Az első a AddTransientHttpErrorPolicy bővítmény használatával ad hozzá újrapróbálkozási szabályzatot. A sikertelen kérelmeket a rendszer akár háromszor is újrapróbálkozza. A második hívás, amely AddTransientHttpErrorPolicy circuit breaker politikát ad hozzá. További külső kérések 30 másodpercig le lesznek tiltva, ha öt sikertelen kísérlet egymás után történik. Az áramkör-megszakító házirendjei állapotalapúak. Az ügyfélen keresztüli összes hívás ugyanazt az áramkör állapotot osztja meg.
Szabályzatok hozzáadása a Polly-beállításjegyzékből
A rendszeresen használt szabályzatok kezelésének egyik módszere az, hogy egyszeri definiálásuk után regisztrálja azokat egy PolicyRegistry. A rendszer egy bővítménymetódust biztosít, amely lehetővé teszi egy kezelő hozzáadását a beállításjegyzékből származó szabályzat használatával:
var registry = services.AddPolicyRegistry();
registry.Add("regular", timeout);
registry.Add("long", longTimeout);
services.AddHttpClient("regulartimeouthandler")
.AddPolicyHandlerFromRegistry("regular");
Az előző kódban két irányelv regisztrálódik, amikor a PolicyRegistry hozzáadásra kerül a ServiceCollection-hez. A beállításjegyzékből származó szabályzat használatához a rendszer a AddPolicyHandlerFromRegistry metódust használja, és átadja az alkalmazandó szabályzat nevét.
A Polly-integrációkkal kapcsolatos IHttpClientFactory további információk a Polly wikiben találhatók.
HttpClient és élettartam-kezelése
Minden alkalommal egy új HttpClient példányt ad vissza, amikor a CreateClient-n meghívják a IHttpClientFactory-t. Van egy HttpMessageHandler megnevezett ügyfél. A gyár kezeli az HttpMessageHandler példányok élettartamát.
IHttpClientFactory összegyűjti a gyár által létrehozott HttpMessageHandler példányokat az erőforrás-felhasználás csökkentése érdekében. A HttpMessageHandler példányok újra felhasználhatók a készletből egy új HttpClient példány létrehozásakor, ha az élettartama még nem járt le.
A kezelők készletezése kívánatos, mivel az egyes kezelők általában saját mögöttes HTTP-kapcsolatokat kezelnek. Ha a szükségesnél több kezelőt hoz létre, az a kapcsolat késéséhez vezethet. Egyes kezelők korlátlan ideig nyitva tartják a kapcsolatokat, ami megakadályozhatja, hogy a kezelő reagáljon a DNS-változásokra.
Az alapértelmezett kezelő élettartama két perc. Az alapértelmezett érték felülírható nevesített ügyfél alapján. A felülbíráláshoz hívja meg a SetHandlerLifetime a IHttpClientBuilder objektumon, amely visszaadásra kerül az ügyfél létrehozásakor.
services.AddHttpClient("extendedhandlerlifetime")
.SetHandlerLifetime(TimeSpan.FromMinutes(5));
Nincs szükség az ügyfél ártalmatlanítására. A felszabadítás megszakítja a kimenő kérelmeket, és garantálja, hogy az adott HttpClient példány nem használható a hívás után Dispose.
IHttpClientFactory nyomon követi és megsemmisíti a HttpClient példányok által használt erőforrásokat. A HttpClient példányok általában olyan .NET-objektumokként kezelhetők, amelyek nem igényelnek ártalmatlanítást.
Egyetlen HttpClient példány hosszú ideig történő életben tartása IHttpClientFactory bevezetése előtti gyakori minta. Ez a minta szükségtelenné válik az IHttpClientFactory rendszerre történő migrálás után.
Az IHttpClientFactory alternatívái
A DI-kompatibilis alkalmazások használata IHttpClientFactory elkerüli a következőt:
- Erőforrás-kimerülési problémák az
HttpMessageHandlerpéldányok összevonásával. - Régi DNS-problémákat orvosolhatunk az
HttpMessageHandlerpéldányok rendszeres időközönkénti újraindításával.
Az előző problémákat többféleképpen is meg lehet oldani egy hosszú élettartamú SocketsHttpHandler példány használatával.
- Hozzon létre egy
SocketsHttpHandlerpéldányt, amikor az alkalmazás elindul, és használja azt az alkalmazás teljes élettartama alatt. - Konfiguráljon PooledConnectionLifetime egy megfelelő értékre a DNS frissítési ideje alapján.
- Hozzon létre
HttpClientpéldányokatnew HttpClient(handler, disposeHandler: false)szükség szerint.
Az előző megközelítések hasonló módon oldják meg azokat az erőforrás-kezelési problémákat, amelyeket a IHttpClientFactory megold.
- A
SocketsHttpHandlermegosztja a kapcsolatokat aHttpClientpéldányok között. Ez a megosztás megakadályozza a foglalatok kimerülését. - A
SocketsHttpHandlera kapcsolatokatPooledConnectionLifetimeszerint ciklusokba rendezi az elavult DNS-problémák elkerülése érdekében.
Cookies
A készletezett HttpMessageHandler példányoknál CookieContainer objektumok megosztása történik. A nem várt CookieContainer objektummegosztás gyakran helytelen kódot eredményez. A cookie-kat igénylő alkalmazások esetében fontolja meg az alábbiakat:
- Az automatikus cookie kezelés letiltása
- Elkerülve
IHttpClientFactory
Hívás ConfigurePrimaryHttpMessageHandler az automatikus cookie kezelés letiltására:
services.AddHttpClient("configured-disable-automatic-cookies")
.ConfigurePrimaryHttpMessageHandler(() =>
{
return new HttpClientHandler()
{
UseCookies = false,
};
});
Logging
Az ügyfelek, akik a IHttpClientFactory segítségével lettek létrehozva, naplóüzeneteket rögzítenek az összes kéréshez. A naplózási konfigurációban engedélyezze a megfelelő információs szintet az alapértelmezett naplóüzenetek megtekintéséhez. A további naplózás, például a kérelemfejlécek naplózása csak nyomkövetési szinten szerepel.
Az egyes ügyfelekhez használt naplókategória tartalmazza az ügyfél nevét. Egy MyNamedClient nevű ügyfél például naplózza az üzeneteket a következő kategóriával System.Net.Http.HttpClient.MyNamedClient.LogicalHandler: . A LogicalHandlerrel utótaggal ellátott üzenetek a kérelemkezelő folyamaton kívülre kerülnek. A kéréskor a rendszer az üzeneteket naplózza, mielőtt a folyamat többi kezelője feldolgozta volna. A válaszban az üzenetek naplózva lesznek, miután bármely más folyamatkezelő megkapta a választ.
A naplózás a kérelemkezelő folyamaton belül is megtörténik. A MyNamedClient példában ezek az üzenetek a naplókategória System.Net.Http.HttpClient.MyNamedClient.ClientHandlerszerint vannak naplózva. A kérés esetében ez akkor történik, miután az összes többi kezelő végrehajtotta a feladatát, és közvetlenül azelőtt, hogy a kérést elküldenék a hálózatra. A válaszban ez a naplózás a válasz állapotát is tartalmazza, mielőtt az áthalad a kezelőfolyamaton.
A folyamaton kívüli és a folyamaton belüli naplózás engedélyezése lehetővé teszi a többi folyamatkezelő által végrehajtott módosítások ellenőrzését. Ilyen lehet például a kérelemfejlécek vagy a válaszállapot-kód módosítása.
Ha szükséges, a naplókategória tartalmazza az ügyfél nevét, lehetővé teszi a naplószűrést adott nevesített ügyfelek esetében.
A HttpMessageHandler konfigurálása
Szükség lehet az ügyfél által használt belső HttpMessageHandler konfiguráció szabályozására.
A rendszer névvel ellátott vagy beírt ügyfelek hozzáadásakor ad vissza egy IHttpClientBuilder hibát. A ConfigurePrimaryHttpMessageHandler bővítménymetódus használható meghatalmazott definiálására. A meghatalmazott az ügyfél által használt elsődleges HttpMessageHandler kiszolgáló létrehozásához és konfigurálásához használható:
services.AddHttpClient("configured-inner-handler")
.ConfigurePrimaryHttpMessageHandler(() =>
{
return new HttpClientHandler()
{
AllowAutoRedirect = false,
UseDefaultCredentials = true
};
});
Az IHttpClientFactory használata konzolalkalmazásban
Egy konzolalkalmazásban adja hozzá a következő csomaghivatkozásokat a projekthez:
Az alábbi példában:
- IHttpClientFactory regisztrálva van a Generic Host szolgáltatáskonténerében.
-
MyServicelétrehoz egy ügyfél-előállító példányt a szolgáltatás alapján, amelyet egyHttpClientlétrehozásához használnak.HttpClientweblap lekérésére szolgál. - A szolgáltatás metódusa
GetPagea weblap tartalmának első 500 karakterét írja a konzolra. További információ a szolgáltatások meghívásárólProgram.Main: Függőséginjektálás a ASP.NET Core-ban.
using System;
using System.Net.Http;
using System.Threading.Tasks;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging;
class Program
{
static async Task<int> Main(string[] args)
{
var builder = new HostBuilder()
.ConfigureServices((hostContext, services) =>
{
services.AddHttpClient();
services.AddTransient<IMyService, MyService>();
}).UseConsoleLifetime();
var host = builder.Build();
try
{
var myService = host.Services.GetRequiredService<IMyService>();
var pageContent = await myService.GetPage();
Console.WriteLine(pageContent.Substring(0, 500));
}
catch (Exception ex)
{
var logger = host.Services.GetRequiredService<ILogger<Program>>();
logger.LogError(ex, "An error occurred.");
}
return 0;
}
public interface IMyService
{
Task<string> GetPage();
}
public class MyService : IMyService
{
private readonly IHttpClientFactory _clientFactory;
public MyService(IHttpClientFactory clientFactory)
{
_clientFactory = clientFactory;
}
public async Task<string> GetPage()
{
// Content from BBC One: Dr. Who website (©BBC)
var request = new HttpRequestMessage(HttpMethod.Get,
"https://www.bbc.co.uk/programmes/b006q2x0");
var client = _clientFactory.CreateClient();
var response = await client.SendAsync(request);
if (response.IsSuccessStatusCode)
{
return await response.Content.ReadAsStringAsync();
}
else
{
return $"StatusCode: {response.StatusCode}";
}
}
}
}
Élőfej propagálása köztes szoftver
A fejléc propagálása egy közösség által támogatott köztes szoftver, amely a HTTP-fejléceket a bejövő kérésből a kimenő HTTP-ügyfélkérelmekbe továbbítja. A fejlécpropagálás használata:
Hivatkozzon a Fejlécpropagation csomag közösség által támogatott portjára. ASP.NET Core 3.1 vagy újabb verziója támogatja a Microsoft.AspNetCore.HeaderPropagationt.
Konfigurálja a köztes szoftvert és
HttpClienta(z)Startupsorban.public void ConfigureServices(IServiceCollection services) { services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_1); services.AddHttpClient("MyForwardingClient").AddHeaderPropagation(); services.AddHeaderPropagation(options => { options.Headers.Add("X-TraceId"); }); } public void Configure(IApplicationBuilder app, IHostingEnvironment env) { if (env.IsDevelopment()) { app.UseDeveloperExceptionPage(); } else { app.UseHsts(); } app.UseHttpsRedirection(); app.UseHeaderPropagation(); app.UseMvc(); }Az ügyfél tartalmazza a konfigurált fejléceket a kimenő kérelmekhez:
var client = clientFactory.CreateClient("MyForwardingClient"); var response = client.GetAsync(...);