IHttpClientFactory a .NET-tel
Ebből a cikkből megtudhatja, hogyan hozhat létre IHttpClientFactory
típusok különböző .NET-alapokat, például a függőséginjektálást (DI), a naplózást és a konfigurációt az interfész használatávalHttpClient
. A HttpClient típust a 2012-ben megjelent .NET-keretrendszer 4.5-ben vezették be. Más szóval, már egy ideje itt van.
HttpClient
HTTP-kérések készítésére és a http-válaszok kezelésére szolgál a Uriweberőforrások által azonosított . A HTTP protokoll az internetes forgalom túlnyomó többségét teszi ki.
Az ajánlott eljárásokat hajtó modern alkalmazásfejlesztési alapelvek a gyár absztrakciójaként szolgálnak, IHttpClientFactory amely egyéni konfigurációkkal rendelkező példányokat hozhat létre HttpClient
.
IHttpClientFactory a .NET Core 2.1-ben jelent meg. A gyakori HTTP-alapú .NET-számítási feladatok könnyedén kihasználhatják a rugalmas és átmeneti hibakezelési külső köztes szoftver előnyeit.
Feljegyzés
Ha az alkalmazás cookie-kat igényel, érdemes lehet elkerülni a használatot IHttpClientFactory az alkalmazásban. Az ügyfelek kezelésének alternatív módjaiért tekintse meg a HTTP-ügyfelek használatának irányelveit.
Fontos
A létrehozott HttpClient
példányok élettartam-kezelése IHttpClientFactory
teljesen eltér a manuálisan létrehozott példányoktól. A stratégiák a beállított vagy hosszú élettartamú ügyfelek által PooledConnectionLifetime
További információkért tekintse meg a HttpClient élettartam-kezelési szakaszát és a HTTP-ügyfelek használatának irányelveit.
A IHttpClientFactory
típus
A cikkben szereplő összes mintaforráskódhoz telepíteni kell a Microsoft.Extensions.Http
NuGet-csomagot. A példakódok emellett azt is bemutatják, hogy a http-kérések GET
használatával lekérhetők a felhasználói Todo
objektumok az ingyenes {JSON} helyőrző API-ból.
Amikor meghívja bármelyik AddHttpClient bővítménymetelyt, hozzáadja a IHttpClientFactory
kapcsolódó szolgáltatásokat a IServiceCollection. A IHttpClientFactory
típus a következő előnyöket kínálja:
- Az osztályt
HttpClient
DI-kész típusként teszi elérhetővé. - Központi helyet biztosít a logikai
HttpClient
példányok elnevezéséhez és konfigurálásához. - Kodifikálja a kimenő köztes szoftver fogalmát a
HttpClient
delegáló kezelőinek használatával. - A Polly-alapú köztes szoftver bővítménymetelyeket biztosít a kezelők delegálásának előnyeinek kihasználásához.
HttpClient
- Kezeli a mögöttes HttpClientHandler példányok gyorsítótárazását és élettartamát. Az automatikus felügyelet elkerüli az élettartamok manuális kezelésekor
HttpClient
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.
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
A regisztrációhoz hívja meg a IHttpClientFactory
következőt AddHttpClient
:
using Shared;
using BasicHttp.Example;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging;
HostApplicationBuilder builder = Host.CreateApplicationBuilder(args);
builder.Services.AddHttpClient();
builder.Services.AddTransient<TodoService>();
using IHost host = builder.Build();
A szolgáltatások használatához konstruktorparaméterre lehet szükség a IHttpClientFactory
DI használatával. A következő kód egy példány létrehozásához IHttpClientFactory
használHttpClient
:
using System.Net.Http.Json;
using System.Text.Json;
using Microsoft.Extensions.Logging;
using Shared;
namespace BasicHttp.Example;
public sealed class TodoService(
IHttpClientFactory httpClientFactory,
ILogger<TodoService> logger)
{
public async Task<Todo[]> GetUserTodosAsync(int userId)
{
// Create the client
using HttpClient client = httpClientFactory.CreateClient();
try
{
// Make HTTP GET request
// Parse JSON response deserialize into Todo types
Todo[]? todos = await client.GetFromJsonAsync<Todo[]>(
$"https://jsonplaceholder.typicode.com/todos?userId={userId}",
new JsonSerializerOptions(JsonSerializerDefaults.Web));
return todos ?? [];
}
catch (Exception ex)
{
logger.LogError("Error getting something fun to say: {Error}", ex);
}
return [];
}
}
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
a példányok egy meglévő alkalmazásban jönnek létre, cserélje le ezeket az előfordulásokat a következő CreateClienthí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ő felhasználási módja
HttpClient
van. - Sok
HttpClient
példány különböző konfigurációval rendelkezik.
A névvel ellátott HttpClient
konfiguráció a következő regisztráció IServiceCollection
során adható meg:
using Shared;
using NamedHttp.Example;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging;
HostApplicationBuilder builder = Host.CreateApplicationBuilder(args);
string? httpClientName = builder.Configuration["TodoHttpClientName"];
ArgumentException.ThrowIfNullOrEmpty(httpClientName);
builder.Services.AddHttpClient(
httpClientName,
client =>
{
// Set the base address of the named client.
client.BaseAddress = new Uri("https://jsonplaceholder.typicode.com/");
// Add a user-agent default request header.
client.DefaultRequestHeaders.UserAgent.ParseAdd("dotnet-docs");
});
Az előző kódban az ügyfél a következőkkel van konfigurálva:
- A konfigurációból lekért név a
"TodoHttpClientName"
. - Az alapcím
https://jsonplaceholder.typicode.com/
. - Egy
"User-Agent"
fejléc.
A konfigurációval megadhatja a HTTP-ügyfélneveket, ami segít elkerülni az ügyfelek helytelen elnevezését a hozzáadáskor és a létrehozáskor. Ebben a példában a appsettings.json fájl használatával konfigurálja a HTTP-ügyfél nevét:
{
"TodoHttpClientName": "JsonPlaceholderApi"
}
Egyszerűen bővítheti ezt a konfigurációt, és további részleteket tárolhat arról, hogy hogyan szeretné a HTTP-ügyfél működését. További információ: Konfiguráció a .NET-ben.
Ügyfél létrehozása
Minden alkalommal CreateClient a következőt hívjuk meg:
- 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 a nevét a következőbe CreateClient
:
using System.Net.Http.Json;
using System.Text.Json;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.Logging;
using Shared;
namespace NamedHttp.Example;
public sealed class TodoService
{
private readonly IHttpClientFactory _httpClientFactory = null!;
private readonly IConfiguration _configuration = null!;
private readonly ILogger<TodoService> _logger = null!;
public TodoService(
IHttpClientFactory httpClientFactory,
IConfiguration configuration,
ILogger<TodoService> logger) =>
(_httpClientFactory, _configuration, _logger) =
(httpClientFactory, configuration, logger);
public async Task<Todo[]> GetUserTodosAsync(int userId)
{
// Create the client
string? httpClientName = _configuration["TodoHttpClientName"];
using HttpClient client = _httpClientFactory.CreateClient(httpClientName ?? "");
try
{
// Make HTTP GET request
// Parse JSON response deserialize into Todo type
Todo[]? todos = await client.GetFromJsonAsync<Todo[]>(
$"todos?userId={userId}",
new JsonSerializerOptions(JsonSerializerDefaults.Web));
return todos ?? [];
}
catch (Exception ex)
{
_logger.LogError("Error getting something fun to say: {Error}", ex);
}
return [];
}
}
Az előző kódban a HTTP-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.
- Nyújtson segítséget az IntelliSense és a fordító számára az ügyfelek használatakor.
- Adjon meg egyetlen helyet egy adott
HttpClient
hely konfigurálásához és használatához. Használhat például egyetlen beírt ügyfelet:- Egyetlen háttérvégponthoz.
- 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 elfogad egy paramétert HttpClient
a konstruktorban:
using System.Net.Http.Json;
using System.Text.Json;
using Microsoft.Extensions.Logging;
using Shared;
namespace TypedHttp.Example;
public sealed class TodoService(
HttpClient httpClient,
ILogger<TodoService> logger) : IDisposable
{
public async Task<Todo[]> GetUserTodosAsync(int userId)
{
try
{
// Make HTTP GET request
// Parse JSON response deserialize into Todo type
Todo[]? todos = await httpClient.GetFromJsonAsync<Todo[]>(
$"todos?userId={userId}",
new JsonSerializerOptions(JsonSerializerDefaults.Web));
return todos ?? [];
}
catch (Exception ex)
{
logger.LogError("Error getting something fun to say: {Error}", ex);
}
return [];
}
public void Dispose() => httpClient?.Dispose();
}
A fenti kód a következőket végzi el:
- A konfiguráció akkor van beállítva, amikor a beírt ügyfél hozzá lesz adva a szolgáltatásgyűjteményhez.
- Ez
HttpClient
osztályhatókörű változóként (mezőként) van hozzárendelve, és a közzétett API-kkal együtt használatos.
Olyan API-specifikus metódusok hozhatók létre, amelyek elérhetővé HttpClient
teszik a funkciókat. A metódus például beágyazza a GetUserTodosAsync
kódot a felhasználóspecifikus Todo
objektumok lekéréséhez.
A következő kódhívások AddHttpClient egy beírt ügyfélosztály regisztrálásához:
using Shared;
using TypedHttp.Example;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging;
HostApplicationBuilder builder = Host.CreateApplicationBuilder(args);
builder.Services.AddHttpClient<TodoService>(
client =>
{
// Set the base address of the typed client.
client.BaseAddress = new Uri("https://jsonplaceholder.typicode.com/");
// Add a user-agent default request header.
client.DefaultRequestHeaders.UserAgent.ParseAdd("dotnet-docs");
});
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 TodoService
. Ez a regisztráció egy gyári módszert használ a következő célokra:
- Hozza létre a
HttpClient
egy példányát. - Hozzon létre egy példányt
TodoService
, amely átmegy a példányon a konstruktornakHttpClient
.
Fontos
A gépelt ügyfelek használata az önálló szolgáltatásokban veszélyes lehet. További információkért tekintse meg a Beírt ügyfelek elkerülése a singleton services szakaszban található szakaszt.
Feljegyzés
Ha gépelt ügyfelet regisztrál a AddHttpClient<TClient>
metódussal, a TClient
típusnak olyan konstruktorral kell rendelkeznie, amely paraméterként elfogad egy HttpClient
konstruktort. Emellett a TClient
típust nem szabad külön regisztrálni a DI-tárolóban, mivel ez azt eredményezi, hogy a későbbi regisztráció felülírja az előbbit.
Létrehozott ügyfelek
IHttpClientFactory
külső kódtárakkal, például a Refittel együtt használható. A Refit egy REST-kódtár a .NET-hez. Lehetővé teszi a deklaratív REST API-definíciókat, a végpontokhoz való leképezési felületi metódusokat. A felület implementációját a külső HTTP-hívások végrehajtásával dinamikusan RestService
HttpClient
hozza létre a rendszer.
Vegye figyelembe a következő record
típust:
namespace Shared;
public record class Todo(
int UserId,
int Id,
string Title,
bool Completed);
Az alábbi példa a Refit.HttpClientFactory
NuGet-csomagra támaszkodik, és egy egyszerű felület:
using Refit;
using Shared;
namespace GeneratedHttp.Example;
public interface ITodoService
{
[Get("/todos?userId={userId}")]
Task<Todo[]> GetUserTodosAsync(int userId);
}
Az előző C#-felület:
- Egy példányt visszaadó
GetUserTodosAsync
metódustTask<Todo[]>
definiál. - Deklarál egy
Refit.GetAttribute
attribútumot a külső API elérési útjával és lekérdezési sztringjével.
Egy beírt ügyfél hozzáadható a Refit használatával a megvalósítás létrehozásához:
using GeneratedHttp.Example;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging;
using Refit;
using Shared;
HostApplicationBuilder builder = Host.CreateApplicationBuilder(args);
builder.Services.AddRefitClient<ITodoService>()
.ConfigureHttpClient(client =>
{
// Set the base address of the named client.
client.BaseAddress = new Uri("https://jsonplaceholder.typicode.com/");
// Add a user-agent default request header.
client.DefaultRequestHeaders.UserAgent.ParseAdd("dotnet-docs");
});
A definiált felület szükség esetén felhasználható a DI és a Refit által biztosított implementációval.
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: . A HTTP-kérések küldéséről további információt a HttpClient használatával történő kérés küldése című témakörben talál.
Az alábbi példa bemutatja, hogyan lehet HTTP-kérést POST
küldeni:
public async Task CreateItemAsync(Item item)
{
using StringContent json = new(
JsonSerializer.Serialize(item, new JsonSerializerOptions(JsonSerializerDefaults.Web)),
Encoding.UTF8,
MediaTypeNames.Application.Json);
using HttpResponseMessage httpResponse =
await httpClient.PostAsync("/api/items", json);
httpResponse.EnsureSuccessStatusCode();
}
Az előző kódban a CreateItemAsync
metódus:
- Szerializálja a paramétert
Item
A JSON használatávalSystem.Text.Json
. Ez egy példányt JsonSerializerOptions használ a szerializálási folyamat konfigurálásához. - 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.
- Kivételt jelölő hívások EnsureSuccessStatusCode , 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-kérést PUT
mutat be:
public async Task UpdateItemAsync(Item item)
{
using StringContent json = new(
JsonSerializer.Serialize(item, new JsonSerializerOptions(JsonSerializerDefaults.Web)),
Encoding.UTF8,
MediaTypeNames.Application.Json);
using HttpResponseMessage httpResponse =
await httpClient.PutAsync($"/api/items/{item.Id}", json);
httpResponse.EnsureSuccessStatusCode();
}
Az előző kód nagyon hasonlít a POST
példához. A UpdateItemAsync
metódus hívása PutAsync ahelyett, hogy PostAsync
.
Az alábbi példa egy HTTP-kérést DELETE
mutat be:
public async Task DeleteItemAsync(Guid id)
{
using HttpResponseMessage httpResponse =
await httpClient.DeleteAsync($"/api/items/{id}");
httpResponse.EnsureSuccessStatusCode();
}
Az előző kódban a metódus meghívja a metódust DeleteItemAsync
DeleteAsync. Mivel a HTTP DELETE-kérelmek általában nem tartalmaznak törzset, a DeleteAsync
metódus nem biztosít túlterhelést, amely elfogadja a példányt HttpContent
.
Ha többet szeretne megtudni a különböző HTTP-parancsok HttpClient
használatáról, tekintse meg a következőt HttpClient:
HttpClient
élettartam-kezelés
A rendszer minden alkalommal új HttpClient
példányt ad vissza, amikor CreateClient
a rendszer meghívja a IHttpClientFactory
. Ügyfélnévenként egy HttpClientHandler példány jön létre. A gyár kezeli a példányok élettartamát HttpClientHandler
.
IHttpClientFactory
gyorsítótárazza a HttpClientHandler
gyár által létrehozott példányokat az erőforrás-felhasználás csökkentése érdekében. A HttpClientHandler
példányok újra felhasználhatók a gyorsítótárból egy új HttpClient
példány létrehozásakor, ha az élettartama nem járt le.
A kezelők gyorsítótárazása kívánatos, mivel az egyes kezelők általában a saját mögöttes HTTP-kapcsolatkészletét kezelik. A szükségesnél több kezelő létrehozása a szoftvercsatornák kimerülését és a csatlakozási késéseket eredményezheti. 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ülbírálásához hívja meg SetHandlerLifetime az egyes ügyfeleket a IServiceCollection
következőn:
services.AddHttpClient("Named.Client")
.SetHandlerLifetime(TimeSpan.FromMinutes(5));
Fontos
HttpClient
a létrehozott IHttpClientFactory
példányok rövid élettartamúak.
HttpMessageHandler
A dns-változásokra való reagálás biztosításáhozIHttpClientFactory
elengedhetetlen, hogy a kezelők az élettartamuk lejártakor újra feldolgozhassák azokat.HttpClient
létrehozásakor egy adott kezelőpéldányhoz van kötve, ezért az újHttpClient
példányokat időben kell kérni annak biztosítása érdekében, hogy az ügyfél megkapja a frissített kezelőt.A gyár által létrehozott ilyen
HttpClient
példányok megsemmisítése nem vezet aljzatkimerüléshez, mivel az ártalmatlanítása nem váltja ki aHttpMessageHandler
.IHttpClientFactory
nyomon követi és megsemmisíti a példányok, különösen aHttpClient
példányok létrehozásáhozHttpMessageHandler
használt erőforrásokat, amint lejár az élettartamuk, és már nincsHttpClient
használatban.
Az egyetlen HttpClient
példány hosszú ideig való életben tartása gyakori minta, amely alternatívaként IHttpClientFactory
használható, azonban ehhez a mintához további beállításokra van szükség, például .PooledConnectionLifetime
Használhatja a hosszú élettartamú ügyfeleket PooledConnectionLifetime
, vagy a rövid élettartamú ügyfeleket, amelyeket a következő IHttpClientFactory
hozott létre: . A HTTP-ügyfelek használatának irányelvei című témakörből megtudhatja, hogy melyik stratégiát érdemes használni az alkalmazásban.
Konfigurálja a HttpMessageHandler
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ódussal megadhatja a delegáltat a IServiceCollection
. A meghatalmazott az ügyfél által használt elsődleges HttpMessageHandler
kiszolgáló létrehozásához és konfigurálásához használható:
.ConfigurePrimaryHttpMessageHandler(() =>
{
return new HttpClientHandler
{
AllowAutoRedirect = false,
UseDefaultCredentials = true
};
});
HttClientHandler
A konfigurálás lehetővé teszi a példány proxyjának megadását a HttpClient
kezelő különböző egyéb tulajdonságai között. További információ: Proxy per client.
További konfiguráció
A következő konfigurációs lehetőségek IHttpClientHandler
közül választhat:
Metódus | Leírás |
---|---|
AddHttpMessageHandler | Hozzáad egy további üzenetkezelőt egy elnevezetthez HttpClient . |
AddTypedClient | Konfigurálja a kötést a TClient HttpClient IHttpClientBuilder . |
ConfigureHttpClient | Hozzáad egy meghatalmazottat, aki egy elnevezett HttpClient konfigurálásához lesz használva. |
ConfigurePrimaryHttpMessageHandler | Konfigurálja az elsődlegest HttpMessageHandler a függőséginjektálási tárolóból egy nevesített HttpClient tárolóhoz. |
RedactLoggedHeaders | Beállítja azoknak a HTTP-fejlécneveknek a gyűjteményét, amelyek értékeit a naplózás előtt újra ki kell léptetni. |
SetHandlerLifetime | A példányok újrafelhasználásának időtartamát HttpMessageHandler adja meg. Minden megnevezett ügyfél saját konfigurált kezelői élettartam-értékkel rendelkezhet. |
UseSocketsHttpHandler | Konfigurál egy új vagy egy korábban hozzáadott SocketsHttpHandler példányt a függőséginjektálási tárolóból úgy, hogy a névvel ellátott HttpClient tároló elsődleges kezelője legyen. (csak.NET 5+) |
Az IHttpClientFactory és a SocketsHttpHandler együttes használata
A SocketsHttpHandler
megvalósítás a HttpMessageHandler
.NET Core 2.1-ben lett hozzáadva, amely lehetővé teszi PooledConnectionLifetime
a konfigurálást. Ezzel a beállítással biztosítható, hogy a kezelő reagáljon a DNS-változásokra, ezért a használat SocketsHttpHandler
alternatívának minősül IHttpClientFactory
. További információt a HTTP-ügyfelek használatának irányelvei című témakörben talál.
A konfigurálhatóság azonban SocketsHttpHandler
IHttpClientFactory
együtt is használható. Mindkét API használatával kihasználhatja a konfigurálhatóságot alacsony szinten (például dinamikus tanúsítványkiválasztáshoz) LocalCertificateSelectionCallback
és magas szinten (például a DI-integráció és több ügyfélkonfiguráció kihasználásával).
Mindkét API használata:
- Adja meg a
SocketsHttpHandler
PrimaryHandler> vagy ConfigurePrimaryHttpMessageHandler a (csak.NET 5+) lehetőségetUseSocketsHttpHandler. - Állítsa be SocketsHttpHandler.PooledConnectionLifetime a DNS frissítésének várható időköze alapján, például egy korábban megadott
HandlerLifetime
értékre. - (Nem kötelező) Mivel
SocketsHttpHandler
kezelni fogja a kapcsolatkészletezést és az újrahasznosítást, már nincs szükség kezelői újrahasznosításra aIHttpClientFactory
szinten. Letilthatja a következő beállítássalHandlerLifetime
Timeout.InfiniteTimeSpan
: .
services.AddHttpClient(name)
.UseSocketsHttpHandler((handler, _) =>
handler.PooledConnectionLifetime = TimeSpan.FromMinutes(2)) // Recreate connection every 2 minutes
.SetHandlerLifetime(Timeout.InfiniteTimeSpan); // Disable rotation, as it is handled by PooledConnectionLifetime
A fenti példában a rendszer 2 percet választott tetszőlegesen illusztrációs célokra, az alapértelmezett HandlerLifetime
értékhez igazítva. Az értéket a DNS vagy más hálózati változások várható gyakorisága alapján kell kiválasztania. További információkért tekintse meg az irányelvek DNS-viselkedési szakaszát HttpClient
és az API dokumentációjának Megjegyzések szakaszát PooledConnectionLifetime .
A gépelt ügyfelek elkerülése az önálló szolgáltatásokban
Az elnevezett ügyfél-megközelítés IHttpClientFactory
rendszer a szolgáltatásokba injektálja a példányokat, és HttpClient
minden alkalommal meghívja CreateClient a példányokat, amikor HttpClient
szükség van rá.
A gépelt ügyfél megközelítésével azonban a gépelt ügyfelek általában átmeneti objektumok, amelyeket általában a szolgáltatásokba injektálnak. Ez problémát okozhat, mert egy gépelt ügyfél injektálható egy singleton szolgáltatásba.
Fontos
A gépelt ügyfelek várhatóan rövid élettartamúak lesznek, ugyanúgy, mint az általuk HttpClient
létrehozott példányok (további információ: HttpClient
). Amint létrejön egy beírt ügyfélpéldány, IHttpClientFactory
nincs rá vezérlése. Ha egy gépelt ügyfélpéldányt egyetlenton rögzít, az megakadályozhatja, hogy reagáljon a DNS-változásokra, és az egyik célt legyőzze IHttpClientFactory
.
Ha példányokat kell használnia HttpClient
egy singleton szolgáltatásban, vegye figyelembe a következő lehetőségeket:
- Ehelyett használja az elnevezett ügyfél megközelítést, injektálva
IHttpClientFactory
az egyszeri szolgáltatásba, és szükség esetén újra kell dolgozniaHttpClient
a példányokat. - Ha a beírt ügyfél megközelítést szeretné használni, használja
SocketsHttpHandler
elsődleges kezelőként konfigurálvaPooledConnectionLifetime
. A használattalSocketsHttpHandler
IHttpClientFactory
kapcsolatos további információkért tekintse meg az IHttpClientFactory és a SocketsHttpHandler együttes használatát ismertető szakaszt.
Üzenetkezelő hatókörök az IHttpClientFactory-ban
IHttpClientFactory
minden HttpMessageHandler
példányhoz külön DI-hatókört hoz létre. Ezek a DI-hatókörök eltérnek az alkalmazás DI-hatóköreitől (például ASP.NET bejövő kérelem hatókörétől vagy egy felhasználó által létrehozott manuális DI-hatókörtől), így nem osztanak meg hatókörrel rendelkező szolgáltatáspéldányokat. Az Üzenetkezelő hatókörei a kezelő élettartamához vannak kötve, és túlléphetik az alkalmazás hatóköreit, ami például azt eredményezheti, hogy ugyanazt HttpMessageHandler
a példányt ugyanazzal az injektált hatókörű függőséggel használja fel több bejövő kérés között.
A felhasználók számára erősen ajánlott , hogy ne gyorsítótárazza a hatókörrel kapcsolatos információkat (például az adatokat HttpContext
) a példányokon belül HttpMessageHandler
, és körültekintően használja a hatókörrel rendelkező függőségeket a bizalmas információk kiszivárgásának elkerülése érdekében.
Ha az üzenetkezelőtől szeretne hozzáférést kérni egy alkalmazás DI-hatóköréhez, a hitelesítéshez például a hatókör-tudatos logikát egy külön átmenetibe DelegatingHandler
ágyazná be, és körbefuttatná egy HttpMessageHandler
példány körül a IHttpClientFactory
gyorsítótárból. A regisztrált IHttpMessageHandlerFactory.CreateHandler kezelői hívásának elérése. Ebben az esetben saját maga hoz létre egy példányt HttpClient
a létrehozott kezelővel.
Az alábbi példa egy hatókörrel rendelkező HttpClient
objektum DelegatingHandler
létrehozását mutatja be:
if (scopeAwareHandlerType != null)
{
if (!typeof(DelegatingHandler).IsAssignableFrom(scopeAwareHandlerType))
{
throw new ArgumentException($"""
Scope aware HttpHandler {scopeAwareHandlerType.Name} should
be assignable to DelegatingHandler
""");
}
// Create top-most delegating handler with scoped dependencies
scopeAwareHandler = (DelegatingHandler)_scopeServiceProvider.GetRequiredService(scopeAwareHandlerType); // should be transient
if (scopeAwareHandler.InnerHandler != null)
{
throw new ArgumentException($"""
Inner handler of a delegating handler {scopeAwareHandlerType.Name} should be null.
Scope aware HttpHandler should be registered as Transient.
""");
}
}
// Get or create HttpMessageHandler from HttpClientFactory
HttpMessageHandler handler = _httpMessageHandlerFactory.CreateHandler(name);
if (scopeAwareHandler != null)
{
scopeAwareHandler.InnerHandler = handler;
handler = scopeAwareHandler;
}
HttpClient client = new(handler);
Egy további kerülő megoldás egy bővítménymetódussal követve regisztrálhat egy hatóköralapú DelegatingHandler
és felülbírált alapértelmezett IHttpClientFactory
regisztrációt egy átmeneti szolgáltatásban, amely hozzáfér az aktuális alkalmazás hatóköréhez:
public static IHttpClientBuilder AddScopeAwareHttpHandler<THandler>(
this IHttpClientBuilder builder) where THandler : DelegatingHandler
{
builder.Services.TryAddTransient<THandler>();
if (!builder.Services.Any(sd => sd.ImplementationType == typeof(ScopeAwareHttpClientFactory)))
{
// Override default IHttpClientFactory registration
builder.Services.AddTransient<IHttpClientFactory, ScopeAwareHttpClientFactory>();
}
builder.Services.Configure<ScopeAwareHttpClientFactoryOptions>(
builder.Name, options => options.HttpHandlerType = typeof(THandler));
return builder;
}
További információt a teljes példában talál.
Kerülje a "gyári alapértelmezett" elsődleges kezelő használatát.
Ebben a szakaszban a "gyári alapértelmezett" elsődleges kezelő kifejezés arra az elsődleges kezelőre vonatkozik, amelyet az alapértelmezett IHttpClientFactory
implementáció (pontosabban az alapértelmezett HttpMessageHandlerBuilder
implementáció) rendel hozzá abban az esetben, ha egyáltalán nincs konfigurálva.
Feljegyzés
A "gyári alapértelmezett" elsődleges kezelőprogram egy implementációs részlet, amely változhat.
❌ AVOID függ egy adott implementációtól, amelyet "gyári alapértelmezettként" használnak (például HttpClientHandler
).
Vannak olyan esetek, amikor ismernie kell az elsődleges kezelő konkrét típusát, különösen akkor, ha osztálykönyvtáron dolgozik. A végfelhasználó konfigurációjának megőrzése mellett érdemes lehet frissíteni például HttpClientHandler
-specifikus tulajdonságokat, például ClientCertificates
, UseCookies
és UseProxy
. Csábító lehet, ha az elsődleges kezelőt a HttpClientHandler
irányítja, ami történt munkával, miközben HttpClientHandler
"gyári alapértelmezett" elsődleges kezelőként használták. Az implementáció részleteitől függően azonban az ilyen áthidaló megoldás törékeny és töréshez kötött.
Ahelyett, hogy a "gyári alapértelmezett" elsődleges kezelőre támaszkodna, a ConfigureHttpClientDefaults
segítségével beállíthat egy "alkalmazás-szintű" alapértelmezett elsődleges kezelőpéldányt:
// Contract with the end-user: Only HttpClientHandler is supported.
// --- "Pre-configure" stage ---
// The default is fixed as HttpClientHandler to avoid depending on the "factory-default"
// Primary Handler.
services.ConfigureHttpClientDefaults(b =>
b.ConfigurePrimaryHttpMessageHandler(() => new HttpClientHandler() { UseCookies = false }));
// --- "End-user" stage ---
// IHttpClientBuilder builder = services.AddHttpClient("test", /* ... */);
// ...
// --- "Post-configure" stage ---
// The code can rely on the contract, and cast to HttpClientHandler only.
builder.ConfigurePrimaryHttpMessageHandler((handler, provider) =>
{
if (handler is not HttpClientHandler h)
{
throw new InvalidOperationException("Only HttpClientHandler is supported");
}
h.ClientCertificates.Add(GetClientCert(provider, builder.Name));
//X509Certificate2 GetClientCert(IServiceProvider p, string name) { ... }
});
Másik lehetőségként érdemes lehet ellenőrizni az elsődleges kezelő típusát, és konfigurálni az ügyféltanúsítványokhoz hasonló jellemzőket csak a jól ismert támogató típusok esetében (valószínűleg HttpClientHandler
és SocketsHttpHandler
):
// --- "End-user" stage ---
// IHttpClientBuilder builder = services.AddHttpClient("test", /* ... */);
// ...
// --- "Post-configure" stage ---
// No contract is in place. Trying to configure main handler types supporting client
// certs, logging and skipping otherwise.
builder.ConfigurePrimaryHttpMessageHandler((handler, provider) =>
{
if (handler is HttpClientHandler h)
{
h.ClientCertificates.Add(GetClientCert(provider, builder.Name));
}
else if (handler is SocketsHttpHandler s)
{
s.SslOptions ??= new System.Net.Security.SslClientAuthenticationOptions();
s.SslOptions.ClientCertificates ??= new X509CertificateCollection();
s.SslOptions.ClientCertificates!.Add(GetClientCert(provider, builder.Name));
}
else
{
// Log warning
}
//X509Certificate2 GetClientCert(IServiceProvider p, string name) { ... }
});