Megosztás a következőn keresztül:


Rugalmas HTTP-kérések implementálása az IHttpClientFactory használatával

Borravaló

Ez a tartalom egy részlet a "Tárolóalapú .NET-alkalmazásokhoz készült mikroszolgáltatások architektúrája" című eBookból, amely elérhető a .NET Docs oldalon, vagy ingyenesen letölthető PDF-fájlként, amely offline módban is olvasható.

Konténerizált .NET Alkalmazásokhoz készült mikroszolgáltatási architektúra eBook borító miniatűr.

IHttpClientFactory egy szerződés, amelyet a DefaultHttpClientFactory, egy véleményvezérelt gyár valósít meg, és a .NET Core 2.1 óta elérhető. Ez lehetővé teszi HttpClient példányok létrehozását, amelyeket az alkalmazásokban használhat.

A .NET-ben elérhető eredeti HttpClient-osztálysal kapcsolatos problémák

Az eredeti és jól ismert HttpClient osztály könnyen használható, de bizonyos esetekben sok fejlesztő nem használja megfelelően.

Bár ez az osztály implementálja a IDisposable, a using utasításon belüli deklarálás és példányosítás nem javasolt, mert amikor a HttpClient objektumot megsemmisítik, a mögöttes socket nem kerül azonnali felszabadításra, ami socket kimerülés okozta problémát okozhat. A problémával kapcsolatos további információkért tekintse meg a blogbejegyzést, Helytelenül használja a HttpClientet, és ez destabilizálja a szoftverét.

A HttpClient-t ezért egyszeri példányosításra szánják, és az alkalmazás teljes élettartama alatt felhasználják. Ha minden kéréshez létrehoz egy HttpClient osztályt, az kimeríti a nagy terhelés alatt elérhető foglalatok számát. Ez a probléma SocketException hibákat eredményez. A probléma megoldásának lehetséges módjai a HttpClient objektum önálló vagy statikus létrehozásán alapulnak, amint az ebben a Microsoft httpClient-használaticímű cikkében is ismertetjük. Ez jó megoldás lehet olyan rövid élettartamú konzolalkalmazásokhoz vagy hasonlókhoz, amelyek naponta néhányszor futnak.

Egy másik probléma, amelybe a fejlesztők belefutnak, az HttpClient megosztott példányának használata hosszú ideig futó folyamatokban. Ha a HttpClientet singletonként vagy statikus objektumként példányosítják, nem képes kezelni a DNS-változásokat, ahogyan azt a dotnet/runtime GitHub-tárház számú probléma-ben leírja.

A probléma azonban nem önmagában HttpClient, hanem a HttpClient alapértelmezett konstruktorával kapcsolatos, mivel a HttpMessageHandleregy új konkrét példányát hozza létre, amely szoftvercsatornák kimerülési és a FENT említett DNS-módosítási problémákat tartalmaz.

A fent említett problémák megoldása és HttpClient példányok kezelhetővé tétele érdekében a .NET Core 2.1 két megközelítést vezetett be, amelyek közül az egyik IHttpClientFactory. Ez egy felület, amellyel HttpClient-példányokat konfigurálhat és hozhat létre egy alkalmazásban a Függőséginjektálás (DI) használatával. Emellett a Polly-alapú köztes szoftver bővítményeit is biztosítja, hogy kihasználhassa a HttpClient kezelőinek delegálását.

A másik lehetőség a SocketsHttpHandler használata a konfigurált PooledConnectionLifetime. Ez a módszer a hosszú élettartamú, static vagy egyszeri HttpClient példányokra vonatkozik. A különböző stratégiákról további információt a .NET HttpClient-irányelveit ismertető cikkben talál: .

Polly egy átmeneti hibakezelési könyvtár, amely segít a fejlesztőknek növelni az alkalmazásaik rugalmasságát bizonyos előre definiált szabályzatok könnyen olvasható, szálbiztos használatával.

Az IHttpClientFactory használatának előnyei

A IHttpClientFactoryis megvalósító IHttpMessageHandlerFactoryjelenlegi megvalósítása a következő előnyökkel jár:

  • Központi helyet biztosít a logikai HttpClient objektumok elnevezéséhez és konfigurálásához. Konfigurálhat például egy olyan ügyfelet (szolgáltatásügynököt), amely előre konfigurálva van egy adott mikroszolgáltatás eléréséhez.
  • Kodifikálja a kimenő köztes szoftver fogalmát a HttpClient kezelőinek delegálásával és a Polly-alapú köztes szoftver implementálásával, hogy kihasználhassa a Polly rugalmasságra vonatkozó szabályzatait.
  • HttpClient már rendelkezik a kimenő HTTP-kérésekhez összekapcsolható kezelők delegálásának fogalmával. HTTP-ügyfeleket regisztrálhat a gyárban, és egy Polly-kezelővel alkalmazhatja a Polly-szabályzatokat például újrapróbálkozásra, áramkörmegszakításra és más hasonló esetekre.
  • A HttpMessageHandler élettartamának kezelése az említett problémák elkerülése érdekében, amelyek a HttpClient élettartamának saját kezeléskor merülhetnek fel.

Borravaló

A DI által injektált HttpClient példányok biztonságosan megsemmisíthetők, mivel a kapcsolódó HttpMessageHandler a gyár kezeli. Az injektált HttpClient példányok a DI szempontjából átmeneti, míg a HttpMessageHandler példányok hatókörűtekinthetők. HttpMessageHandler példányok saját DI-hatókörrel rendelkeznek, külön az alkalmazás hatókörétől (például ASP.NET bejövő kérelem hatóköreitől). További információért lásd a következőt: HttpClientFactory használata a .NET-ben.

Jegyzet

A IHttpClientFactory (DefaultHttpClientFactory) megvalósítása szorosan kötődik az Microsoft.Extensions.DependencyInjection NuGet-csomag DI-implementációjához. Ha HttpClient-t DI nélkül vagy más DI-implementációkkal kell használnia, fontolja meg static vagy egy példány HttpClient használatát PooledConnectionLifetime beállítással. További információkért tekintse meg a .NET HttpClient irányelveit: .

Az IHttpClientFactory használatának több módja

Az alkalmazásban többféleképpen is használhatja a IHttpClientFactory:

  • Alapszintű használat
  • Névvel ellátott kliensek használata
  • Típusdefiniált ügyfelek használata
  • Generált ügyfelek használata

A rövidség kedvéért ez az útmutató bemutatja a IHttpClientFactoryhasználatának legstrukturáltabb módját, amely a típus szerinti kliensek (szolgáltatási ügynök mintázat) használata. Azonban minden lehetőség dokumentálva van, és jelenleg szerepel ebben a cikkben, amely a IHttpClientFactory használatávalfoglalkozik.

Jegyzet

Ha az alkalmazás cookie-kat igényel, érdemes lehet elkerülni a IHttpClientFactory használatát az alkalmazásban. Az ügyfelek kezelésének alternatív módjaiért tekintse meg HTTP-ügyfelekhasználatának irányelveit.

Gépelt ügyfelek használata az IHttpClientFactory használatával

Szóval, mi az a "Típusos ügyfél"? Ez csak egy HttpClient, amely előre konfigurálva van bizonyos használatra. Ez a konfiguráció bizonyos értékeket tartalmazhat, például az alapkiszolgálót, a HTTP-fejléceket vagy az időtúllépéseket.

Az alábbi ábra bemutatja, hogyan alkalmazzák a Typed Clients-et a IHttpClientFactory-val.

Diagram, amely bemutatja, hogyan használják a típusos ügyfeleket az IHttpClientFactory szolgáltatással.

8-4. ábra. IHttpClientFactory használata típusos ügyfélosztályokkal.

A fenti képen a (vezérlő vagy ügyfélkód által használt) ClientService a regisztrált HttpClientáltal létrehozott IHttpClientFactory-et használja. Ez a gyár hozzárendel a HttpMessageHandler-hez egy HttpClient-t egy készletből. A HttpClient a Polly szabályzataival konfigurálható a IHttpClientFactory regisztrálásakor a DI-tárolóban, kiterjesztési módszerrel AddHttpClient.

A fenti struktúra konfigurálásához telepítse az alkalmazásba a IHttpClientFactory NuGet-csomagot, amely tartalmazza a Microsoft.Extensions.Http hozzáadását a AddHttpClientszámára készült IServiceCollection bővítménymetódussal. Ez a bővítménymetódus regisztrálja a belső DefaultHttpClientFactory osztályt, amelyet az interfész IHttpClientFactoryegyetlentonként használ. Átmeneti konfigurációt definiál a HttpMessageHandlerBuilderszámára. A készletből vett üzenetkezelőt (HttpMessageHandler objektumot) a gyárból visszaadott HttpClient használja.

A következő kódrészletben láthatja, hogyan használható AddHttpClient() a HttpClienthasználatához szükséges típusos ügyfelek (szolgáltatásügynökök) regisztrálására.

// Program.cs
//Add http client services at ConfigureServices(IServiceCollection services)
builder.Services.AddHttpClient<ICatalogService, CatalogService>();
builder.Services.AddHttpClient<IBasketService, BasketService>();
builder.Services.AddHttpClient<IOrderingService, OrderingService>();

Ha az ügyfélszolgáltatásokat az előző kódrészletben látható módon regisztrálja, a DefaultClientFactory minden szolgáltatáshoz létrehoz egy szabványos HttpClient. A beírt ügyfél átmenetiként van regisztrálva a DI-tárolóban. Az előző kódban AddHttpClient() a CatalogService , BasketService, OrderingService átmeneti szolgáltatásként regisztrálja, hogy közvetlenül, további regisztrációk nélkül lehessen beszúrni és felhasználni őket.

A regisztrációban a példányspecifikus konfigurációt is hozzáadhatja például az alapcím konfigurálásához, és hozzáadhat néhány rugalmassági szabályzatot, ahogy az alábbi ábrán látható:

builder.Services.AddHttpClient<ICatalogService, CatalogService>(client =>
{
    client.BaseAddress = new Uri(builder.Configuration["BaseUrl"]);
})
    .AddPolicyHandler(GetRetryPolicy())
    .AddPolicyHandler(GetCircuitBreakerPolicy());

Ebben a következő példában a fenti szabályzatok egyikének konfigurációját láthatja:

static IAsyncPolicy<HttpResponseMessage> GetRetryPolicy()
{
    return HttpPolicyExtensions
        .HandleTransientHttpError()
        .OrResult(msg => msg.StatusCode == System.Net.HttpStatusCode.NotFound)
        .WaitAndRetryAsync(6, retryAttempt => TimeSpan.FromSeconds(Math.Pow(2, retryAttempt)));
}

A Polly használatával kapcsolatos további részleteket a következő cikkbentalálhat.

HttpClient-élettartamok

Minden alkalommal, amikor a HttpClient-től egy IHttpClientFactory objektumot kap, egy új példányt kap vissza. De minden HttpClient egy HttpMessageHandler használ, amelyet a IHttpClientFactory készletezett és újrafelhasznált az erőforrás-felhasználás csökkentése érdekében, feltéve, hogy a HttpMessageHandleré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; a szükségesnél több kezelő létrehozása kapcsolati késéseket eredményezhet. Egyes kezelők korlátlan ideig nyitva tartják a kapcsolatokat, ami megakadályozhatja, hogy a kezelő reagáljon a DNS-változásokra.

A készlet HttpMessageHandler objektumainak élettartama az a időtartam, amely alatt a készlet egy HttpMessageHandler példánya újra felhasználható. Az alapértelmezett érték két perc, de típusú ügyfélenként felül lehet bírálni. A felülbíráláshoz hívja meg a SetHandlerLifetime()-t az ügyfél létrehozásakor visszaadott IHttpClientBuilder-en, ahogyan az az alábbi kódban látható:

//Set 5 min as the lifetime for the HttpMessageHandler objects in the pool used for the Catalog Typed Client
builder.Services.AddHttpClient<ICatalogService, CatalogService>()
    .SetHandlerLifetime(TimeSpan.FromMinutes(5));

Minden típusok szerinti kliensnek lehet saját konfigurált kezelő élettartamának értéke. Állítsa be az élettartamot InfiniteTimeSpan értékre a kezelőfüggvény lejáratának letiltásához.

Az injektált és konfigurált HttpClientet használó gépelt ügyfélosztályok implementálása

Előző lépésként definiálnia kell a típusos ügyfélosztályokat, például a mintakódban szereplő osztályokat, mint a "BasketService", a "CatalogService", vagy az "OrderingService" stb. A típusos ügyfél egy olyan osztály, amely egy HttpClient objektumot fogad el (a konstruktoron keresztül injektálva), és ezt egy távoli HTTP-szolgáltatás meghívására használja. Például:

public class CatalogService : ICatalogService
{
    private readonly HttpClient _httpClient;
    private readonly string _remoteServiceBaseUrl;

    public CatalogService(HttpClient httpClient)
    {
        _httpClient = httpClient;
    }

    public async Task<Catalog> GetCatalogItems(int page, int take,
                                               int? brand, int? type)
    {
        var uri = API.Catalog.GetAllCatalogItems(_remoteServiceBaseUrl,
                                                 page, take, brand, type);

        var responseString = await _httpClient.GetStringAsync(uri);

        var catalog = JsonConvert.DeserializeObject<Catalog>(responseString);
        return catalog;
    }
}

A beírt ügyfelet (CatalogService a példában) a DI (Dependency Injection) aktiválja, ami azt jelenti, hogy a konstruktorban bármilyen regisztrált szolgáltatást elfogadhat a HttpClientmellett.

Egy gépelt kliens tulajdonképpen egy átmeneti objektum, ami azt jelenti, hogy minden alkalommal, amikor szükség van rá, létrejön egy új példány. Új HttpClient példányt kap minden egyes létrehozáskor. A készlet HttpMessageHandler objektumai azonban azok az objektumok, amelyeket több HttpClient példány újra felhasznál.

A gépelt ügyfélosztályok használata

Végül, miután implementálta a típusosan defíniált osztályokat, regisztrálhatja és konfigurálhatja őket AddHttpClient(). Ezt követően bárhol használhatja őket, ahol a DI szolgáltatásokat injektálja, például a Razor oldalkódjában vagy egy MVC webalkalmazás-vezérlőben, amely az alábbi eShopOnContainers-kódban látható:

namespace Microsoft.eShopOnContainers.WebMVC.Controllers
{
    public class CatalogController : Controller
    {
        private ICatalogService _catalogSvc;

        public CatalogController(ICatalogService catalogSvc) =>
                                                           _catalogSvc = catalogSvc;

        public async Task<IActionResult> Index(int? BrandFilterApplied,
                                               int? TypesFilterApplied,
                                               int? page,
                                               [FromQuery]string errorMsg)
        {
            var itemsPage = 10;
            var catalog = await _catalogSvc.GetCatalogItems(page ?? 0,
                                                            itemsPage,
                                                            BrandFilterApplied,
                                                            TypesFilterApplied);
            //… Additional code
        }

        }
}

Eddig a pontig a fenti kódrészlet csak a szokásos HTTP-kérések végrehajtására szolgáló példát mutatja. A "varázslat" azonban a következő szakaszokban található, ahol bemutatja, hogy az HttpClient által küldött összes HTTP-kérés hogyan rendelkezhet rugalmas szabályzatokkal, például exponenciális visszakapcsolással, megszakítókkal, hitelesítési jogkivonatokat használó biztonsági funkciókkal vagy bármilyen más egyéni funkcióval. Mindez pedig elvégezhető úgy, hogy szabályzatokat ad hozzá, és kezelőket delegál a regisztrált típus-specifikus ügyfelekhez.

További erőforrások