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.
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 DefaultHttpClientFactory
uygulanan 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 IDisposable
rağ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ış PooledConnectionLifetime
ile 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 HttpClient
PooledConnectionLifetime
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 IHttpClientFactory
gö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 IHttpClientFactory
nasıl kullanıldığı gösterilmektedir:
Ş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ı IHttpClientFactory
tarafından oluşturulan bir HttpClient
kullanır. Bu fabrika, HttpMessageHandler
bir havuzdan öğesine HttpClient
bir 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 IHttpClientFactory
iç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ı HttpClient
gereken 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 IHttpClientFactory
her nesne aldığınızda HttpClient
yeni bir örnek döndürülür. Ancak her HttpClient
biri, 'nin kullanım ömrü dolmadığı sürece HttpMessageHandler
kaynak 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
.NET için HttpClient yönergeleri
https://video2.skills-academy.com/en-us/dotnet/fundamentals/networking/http/httpclient-guidelines.NET'te HttpClientFactory Kullanma
https://video2.skills-academy.com/en-us/dotnet/core/extensions/httpclient-factoryASP.NET Core'da HttpClientFactory Kullanma
https://video2.skills-academy.com/aspnet/core/fundamentals/http-requestsGitHub deposunda httpClientFactory
dotnet/runtime
kaynak kodu
https://github.com/dotnet/runtime/tree/release/7.0/src/libraries/Microsoft.Extensions.Http/Polly (.NET dayanıklılığı ve geçici-hata işleme kitaplığı)
https://thepollyproject.azurewebsites.net/