Dayanıklı HTTP isteklerini uygulamak için IHttpClientFactory kullanma

İpucu

Bu içerik, .NET Docs'ta veya çevrimdışı olarak okunabilen ücretsiz indirilebilir bir PDF olarak sağlanan Kapsayıcılı .NET Uygulamaları için .NET Mikro Hizmet Mimarisi e-Kitabı'ndan bir alıntıdır.

.NET Microservices Architecture for Containerized .NET Applications eBook cover thumbnail.

IHttpClientFactory, uygulamalarınızda kullanılacak örnekler oluşturmak HttpClient için .NET Core 2.1'den bu yana kullanılabilen, fikirli bir fabrika tarafından DefaultHttpClientFactoryuygulanan bir sözleşmedir.

.NET'te kullanılabilen özgün HttpClient sınıfıyla ilgili sorunlar

Özgün ve iyi bilinen HttpClient sınıf kolayca kullanılabilir, ancak bazı durumlarda birçok geliştirici tarafından düzgün bir şekilde kullanılmaz.

Bu sınıf uygulamasına IDisposablerağmen, nesnesi using atıldığında HttpClient temel alınan yuva hemen serbest bırakılmadığından bir deyim içinde bildirimde bulunması ve örneklenmesi tercih edilmediğinden yuva tükenme sorununa yol açabilir. Bu sorun hakkında daha fazla bilgi için HttpClient'ı yanlış kullanıyorsunuz ve yazılımınızın istikrarını bozuyor blog gönderisine bakın.

Bu nedenle, HttpClient bir kez örneği oluşturulup bir uygulamanın ömrü boyunca yeniden kullanılması amaçlanmıştır. Her istek için bir HttpClient sınıfın örneklemesi, ağır yükler altında kullanılabilen yuva sayısını tüketir. Bu sorun hatalara SocketException neden olur. Bu sorunu çözmek için olası yaklaşımlar, HttpClient kullanımıyla ilgili bu Microsoft makalesinde açıklandığı gibi nesnenin HttpClient tekil veya statik olarak oluşturulmasını temel alır. Bu, kısa süreli konsol uygulamaları veya benzerleri için günde birkaç kez çalışan iyi bir çözüm olabilir.

Geliştiricilerin uzun süre çalışan işlemlerde paylaşılan bir örneğini HttpClient kullanırken karşılaştıkları bir diğer sorun da bu sorundur. HttpClient'ın tekil veya statik bir nesne olarak örneklendiği bir durumda, dotnet/runtime GitHub deposunun bu sorununda açıklandığı gibi DNS değişikliklerini işleyemiyor.

Bununla birlikte, sorun gerçekten HttpClient her konuda değil, httpclient için varsayılan oluşturucudadır, çünkü yukarıda bahsedilen yuva tükenmesi ve DNS değişiklikleri sorunlarına sahip olan yeni bir somut örneği HttpMessageHandleroluşturur.

Yukarıda bahsedilen sorunları gidermek ve örnekleri yönetilebilir hale getirmek HttpClient için .NET Core 2.1 bunlardan biri olmak üzere IHttpClientFactoryiki yaklaşım kullanıma sunulmuştur. Bağımlılık Ekleme (DI) aracılığıyla bir uygulamada örnekleri yapılandırmak ve oluşturmak HttpClient için kullanılan bir arabirimdir. Ayrıca HttpClient'da işleyicileri temsilci olarak atama avantajından yararlanmak için Polly tabanlı ara yazılım için uzantılar sağlar.

Alternatif olarak yapılandırılmış PooledConnectionLifetimeile kullanabilirsinizSocketsHttpHandler. Bu yaklaşım uzun ömürlü static veya tekil HttpClient örneklere uygulanır. Farklı stratejiler hakkında daha fazla bilgi edinmek için bkz . .NET için HttpClient yönergeleri.

Polly , geliştiricilerin bazı önceden tanımlanmış ilkeleri akıcı ve iş parçacığı açısından güvenli bir şekilde kullanarak uygulamalarına dayanıklılık eklemesine yardımcı olan geçici hata işleme kitaplığıdır.

IHttpClientFactory kullanmanın avantajları

uygulamasını da uygulayan IHttpMessageHandlerFactorygeçerli uygulaması IHttpClientFactoryaşağıdaki avantajları sunar:

  • Mantıksal HttpClient nesneleri adlandırmak ve yapılandırmak için merkezi bir konum sağlar. Örneğin, belirli bir mikro hizmete erişmek için önceden yapılandırılmış bir istemci (Hizmet Aracısı) yapılandırabilirsiniz.
  • Polly'nin dayanıklılık ilkelerinden yararlanmak için içindeki işleyicileri HttpClient temsilci olarak atama ve Polly tabanlı ara yazılım uygulama yoluyla giden ara yazılım kavramını codify.
  • HttpClient zaten giden HTTP istekleri için birbirine bağlanabilecek işleyicileri temsilci olarak belirleme kavramına sahiptir. HTTP istemcilerini fabrikaya kaydedebilir ve Polly işleyicisini kullanarak Yeniden Deneme, CircuitBreakers vb. için Polly ilkelerini kullanabilirsiniz.
  • Yaşam ömürlerini HttpMessageHandler kendiniz yönetirken HttpClient oluşabilecek sorunlardan/sorunlardan kaçınmak için kullanım ömrünü yönetin.

İpucu

HttpClient DI tarafından eklenen örnekler güvenli bir şekilde atılabilir, çünkü ilişkili HttpMessageHandler fabrika tarafından yönetilir. HttpClient Eklenen örnekler DI perspektifinden Geçicidir, örnekler ise HttpMessageHandler Kapsamlı olarak kabul edilebilir. HttpMessageHandler örnekleri, uygulama kapsamlarından (örneğin, gelen istek kapsamları ASP.NET) ayrı kendi DI kapsamlarına sahiptir. Daha fazla bilgi için bkz . .NET'te HttpClientFactory kullanma.

Not

(DefaultHttpClientFactory) uygulaması IHttpClientFactory , NuGet paketindeki DI uygulamasına Microsoft.Extensions.DependencyInjection sıkı bir şekilde bağlıdır. DI olmadan veya diğer DI uygulamalarıyla kullanmanız HttpClient gerekiyorsa, ayarlanmış bir static veya tekil HttpClientPooledConnectionLifetime kullanmayı göz önünde bulundurun. Daha fazla bilgi için bkz . .NET için HttpClient yönergeleri.

IHttpClientFactory'yi kullanmanın birden çok yolu

Uygulamanızda kullanabileceğiniz IHttpClientFactory çeşitli yollar vardır:

  • Temel kullanım
  • Adlandırılmış İstemcileri Kullanma
  • Yazılan İstemcileri Kullanma
  • Oluşturulan İstemcileri Kullanma

Kısa bir süre için bu kılavuz, Türü Belirtilen İstemcileri (Hizmet Aracısı düzeni) kullanmak için kullanılan en yapılandırılmış yolu IHttpClientFactorygösterir. Ancak, tüm seçenekler belgelenmiştir ve şu anda kullanımı kapsayan IHttpClientFactory bu makalede listelenmiştir.

Not

Uygulamanız tanımlama bilgileri gerektiriyorsa, uygulamanızda kullanmaktan IHttpClientFactory kaçınmak daha iyi olabilir. İstemcileri yönetmenin alternatif yolları için bkz. HTTP istemcilerini kullanma yönergeleri

IHttpClientFactory ile Yazılan İstemcileri Kullanma

"Yazılan İstemci" nedir? Yalnızca belirli bir kullanım için önceden yapılandırılmış bir HttpClient öğedir. Bu yapılandırma temel sunucu, HTTP üst bilgileri veya zaman aşımları gibi belirli değerleri içerebilir.

Aşağıdaki diyagramda, Türü Belirtilen İstemcilerin ile IHttpClientFactorynasıl kullanıldığı gösterilmektedir:

Diagram showing how typed clients are used with IHttpClientFactory.

Şekil 8-4. Yazılan İstemci sınıflarıyla kullanma IHttpClientFactory .

Yukarıdaki görüntüde, bir ClientService (denetleyici veya istemci kodu tarafından kullanılan), kayıtlı IHttpClientFactorytarafından oluşturulan bir HttpClient kullanır. Bu fabrika, HttpMessageHandler bir havuzdan öğesine HttpClientbir atar. HttpClient, uzantısı yöntemiyle AddHttpClientDI kapsayıcısında kaydederken IHttpClientFactory Polly'nin ilkeleriyle yapılandırılabilir.

Yukarıdaki yapıyı yapılandırmak için, uzantısı IServiceCollectionyöntemini içeren AddHttpClient NuGet paketini yükleyerek Microsoft.Extensions.Http uygulamanıza ekleyinIHttpClientFactory. Bu uzantı yöntemi, arabirimi IHttpClientFactoryiçin tekil olarak kullanılacak iç DefaultHttpClientFactory sınıfı kaydeder. için HttpMessageHandlerBuildergeçici bir yapılandırma tanımlar. Bir havuzdan alınan bu ileti işleyicisi (HttpMessageHandler nesnesi), fabrikadan döndürülen tarafından HttpClient kullanılır.

Sonraki kod parçacığında, kullanması HttpClientgereken TüreMiş İstemcileri (Hizmet Aracıları) kaydetmek için nasıl AddHttpClient() kullanılabileceğini görebilirsiniz.

// 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>();

İstemci hizmetlerinin önceki kod parçacığında gösterildiği gibi kaydedilmesi, her hizmet için bir standart HttpClient oluşturulmasını DefaultClientFactory sağlar. Yazılan istemci, DI kapsayıcısı ile geçici olarak kaydedilir. Yukarıdaki kodda CatalogService, AddHttpClient() BasketService, OrderingService'i geçici hizmetler olarak kaydeder, böylece ek kayıtlara gerek kalmadan doğrudan eklenebilir ve kullanılabilir.

Örneğin, aşağıdaki gibi temel adresi yapılandırmak ve bazı dayanıklılık ilkeleri eklemek için kayda örneğe özgü yapılandırma da ekleyebilirsiniz:

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

Bu sonraki örnekte, yukarıdaki ilkelerden birinin yapılandırmasını görebilirsiniz:

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

Polly'yi kullanma hakkında daha fazla ayrıntıyı Sonraki makalesinde bulabilirsiniz.

HttpClient yaşam süreleri

öğesinden IHttpClientFactoryher nesne aldığınızda HttpClient yeni bir örnek döndürülür. Ancak her HttpClient biri, 'nin kullanım ömrü dolmadığı sürece HttpMessageHandlerkaynak tüketimini azaltmak için havuza alınmış ve tarafından yeniden kullanılan IHttpClientFactory bir HttpMessageHandler kullanır.

İşleyicilerin havuzu, her işleyici genellikle kendi temel HTTP bağlantılarını yönettiğinden tercih edilir; gerektiğinden daha fazla işleyici oluşturmak bağlantı gecikmelerine neden olabilir. Bazı işleyiciler ayrıca bağlantıları süresiz olarak açık tutar ve bu da işleyicinin DNS değişikliklerine tepki vermesini engelleyebilir.

Havuzdaki HttpMessageHandler nesnelerin ömrü, havuzdaki bir HttpMessageHandler örneğin yeniden kullanılabilmesi için gereken süreye sahiptir. Varsayılan değer iki dakikadır, ancak Türü Belirlenmiş İstemci başına geçersiz kılınabilir. Geçersiz kılmak için, aşağıdaki kodda IHttpClientBuilder gösterildiği gibi istemciyi oluştururken döndürülen öğesini çağırınSetHandlerLifetime():

//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));

Her Türlenmiş İstemci kendi yapılandırılmış işleyici yaşam süresi değerine sahip olabilir. İşleyici süre sonunu devre dışı bırakmak için yaşam süresini InfiniteTimeSpan olarak ayarlayın.

Eklenen ve yapılandırılan HttpClient'ı kullanan Türemiş İstemci sınıflarınızı uygulama

Önceki adım olarak, 'BasketService', 'CatalogService', 'OrderingService' gibi örnek koddaki sınıflar gibi Türü Belirlenmiş İstemci sınıflarınızın tanımlanmış olması gerekir. – Türü Belirlenmiş İstemci, bir nesneyi kabul eden (oluşturucusunda eklenmiş) ve bazı uzak HTTP hizmetini çağırmak için kullanan bir HttpClient sınıftır. Örneğin:

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;
    }
}

Türlenmiş İstemci (CatalogService örnekte) DI (Bağımlılık Ekleme) tarafından etkinleştirilir; yani oluşturucusunda kayıtlı herhangi bir hizmeti kabul edebilir ve buna ek olarak HttpClient.

Türü Belirlenmiş İstemci, etkili bir şekilde geçici bir nesnedir, yani her gerektiğinde yeni bir örnek oluşturulur. Her yapız bir örnek alır HttpClient . Ancak havuzdaki HttpMessageHandler nesneler, birden çok HttpClient örnek tarafından yeniden kullanılan nesnelerdir.

Yazılan İstemci sınıflarınızı kullanma

Son olarak, yazdığınız sınıflar uygulandıktan sonra bunları ile kaydettirebilir ve yapılandırabilirsiniz AddHttpClient(). Bundan sonra, bu hizmetleri Razor sayfa kodu veya eShopOnContainers'ın aşağıdaki kodunda gösterilen bir MVC web uygulaması denetleyicisi gibi DI tarafından eklenen her yerde kullanabilirsiniz:

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
        }

        }
}

Bu noktaya kadar, yukarıdaki kod parçacığı yalnızca normal HTTP istekleri gerçekleştirme örneğini gösterir. Ancak 'magic', tarafından yapılan HttpClient tüm HTTP isteklerinin üstel geri alma, devre kesiciler, kimlik doğrulama belirteçlerini kullanan güvenlik özellikleri ve hatta diğer özel özellikler gibi dayanıklı ilkelere nasıl sahip olabileceğini gösterdiği aşağıdaki bölümlerde gelir. Tüm bunlar yalnızca ilkeler ekleyerek ve kayıtlı Türlenmiş İstemcilerinize işleyicileri temsilci olarak vererek yapılabilir.

Ek kaynaklar