Not
Bu sayfaya erişim yetkilendirme gerektiriyor. Oturum açmayı veya dizinleri değiştirmeyi deneyebilirsiniz.
Bu sayfaya erişim yetkilendirme gerektiriyor. Dizinleri değiştirmeyi deneyebilirsiniz.
Bu makalede, bağımlılık ekleme (DI), günlüğe kaydetme ve yapılandırma gibi çeşitli .NET temel bilgileriyle IHttpClientFactory türleri oluşturmak için HttpClient arabirimini kullanmayı öğreneceksiniz.
HttpClient türü, 2012'de yayımlanan .NET Framework 4.5'te tanıtıldı. Başka bir deyişle, bir süredir buralarda.
HttpClient tarafından tanımlanan Uriweb kaynaklarından HTTP istekleri yapmak ve HTTP yanıtlarını işlemek için kullanılır. HTTP protokolü tüm İnternet trafiğinin büyük çoğunluğunu oluşturur.
Modern uygulama geliştirme ilkelerinin en iyi yöntemleri yönlendirdiği bir ortamda, IHttpClientFactory özel yapılandırmalarla HttpClient örnekleri oluşturabilen bir fabrika soyutlaması olarak hizmet eder.
IHttpClientFactory .NET Core 2.1'de kullanıma sunulmuştur. Yaygın HTTP tabanlı .NET iş yükleri, esnek ve geçici hata işleme üçüncü taraf ara yazılımlarından kolayca yararlanabilir.
Uyarı
Uygulamanız tanımlama bilgileri gerektiriyorsa, IHttpClientFactory kullanmaktan kaçınmanız önerilir. Örneklerin havuz oluşturulması, HttpMessageHandler nesnelerin paylaşılmasına CookieContainer yol açar. Tahmin edilmeyen CookieContainer paylaşım, uygulamanın ilişkisiz bölümleri arasında tanımlama bilgilerini sızdırabilir. Ayrıca, HandlerLifetime süresi dolduğunda işleyici geri dönüştürülür, bu da içinde CookieContainer saklanan tüm tanımlama bilgilerinin kaybolduğu anlamına gelir. İstemcileri yönetmenin alternatif yolları için bkz . HTTP istemcilerini kullanma yönergeleri.
Önemli
HttpClient tarafından oluşturulan IHttpClientFactory örneklerinin yaşam süresi yönetimi, el ile oluşturulan örneklerden tamamen farklıdır. Stratejiler, ya kısa ömürlü müşterilerin IHttpClientFactory tarafından oluşturulmasını ya da uzun ömürlü müşterilerin PooledConnectionLifetime ayarlanmasını içermektedir. Daha fazla bilgi için HttpClient yaşam süresi yönetimi bölümüne ve HTTP istemcilerini kullanma yönergeleri bölümüne bakın.
Türü IHttpClientFactory
Bu makalede sağlanan tüm örnek kaynak kodu NuGet paketinin yüklenmesini Microsoft.Extensions.Http gerektirir. Ayrıca, kod örnekleri, HTTP GET isteklerinin ücretsiz Todo API'sinden kullanıcı nesnelerini almak için nasıl kullanıldığını gösterir.
Uzantı yöntemlerinden herhangi birini AddHttpClient çağırdığınızda, IHttpClientFactory ve ilgili hizmetleri IServiceCollection öğesine eklersiniz. Türü IHttpClientFactory aşağıdaki avantajları sunar:
- sınıfını DI'ye
HttpClienthazır bir tür olarak kullanıma sunar. - Mantıksal
HttpClientörneklerini adlandırmak ve yapılandırmak için merkezi bir konum sağlar. -
HttpClientiçindeki yetki veren işleyiciler aracılığıyla giden ara yazılım kavramını kodlar. - Polly tabanlı ara yazılım için delegasyon işleyicilerinin
HttpClientavantajından yararlanmak amacıyla uzantı yöntemleri sağlar. - Altyapı HttpClientHandler örneklerinin önbelleğe alınmasını ve yaşam süresini yönetir. Otomatik yönetim, yaşam süreleri el ile yönetildiğinde
HttpClientoluşan yaygın Etki Alanı Adı Sistemi (DNS) sorunlarını önler. - Fabrika tarafından oluşturulan istemciler aracılığıyla gönderilen tüm istekler için ILogger aracılığıyla yapılandırılabilir bir günlük deneyimi ekler.
Tüketim desenleri
Bir uygulamada kullanılabilecek çeşitli yollar vardır IHttpClientFactory :
En iyi yaklaşım, uygulamanın gereksinimlerine bağlıdır.
Temel kullanım
IHttpClientFactory öğesini kaydetmek için, AddHttpClient çağırın:
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();
Hizmetlerin tüketilmesi, DI ile oluşturucu parametresi olarak IHttpClientFactoryöğesini gerektirebilir. Aşağıdaki kod, bir IHttpClientFactory örneği oluşturmak için HttpClient kullanır.
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
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 [];
}
}
IHttpClientFactory Yukarıdaki örnekte like kullanmak, mevcut bir uygulamayı yeniden düzenlemenin iyi bir yoludur. Nasıl kullanıldığı üzerinde HttpClient hiçbir etkisi yoktur. Mevcut bir uygulamada instance'ların oluşturulduğu yerlerde HttpClient kullanımlarını CreateClient çağrılarına ile değiştirin.
Adlandırılmış istemciler
Adlandırılmış istemciler şu durumlarda iyi bir seçimdir:
- Uygulamanın birçok farklı
HttpClientkullanımı gerektiriyor. - Birçok
HttpClientörneğin farklı yapılandırmaları vardır.
Adlandırılmış HttpClient için yapılandırma, IServiceCollection üzerinde kayıt sırasında belirtilebilir.
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");
});
Önceki kodda, istemci şu şekilde yapılandırılır:
-
"TodoHttpClientName"altında yapılandırmadan çekilen bir ad. - temel adresi
https://jsonplaceholder.typicode.com/. - Bir
"User-Agent"başlık.
Http istemci adlarını belirtmek için yapılandırmayı kullanabilirsiniz. Bu, ekleyip oluştururken istemcilerin yanlış adlandırılmasını önlemeye yardımcı olur. Bu örnekte, http istemci adını yapılandırmak için appsettings.json dosyası kullanılır:
{
"TodoHttpClientName": "JsonPlaceholderApi"
}
Bu yapılandırmayı genişletmek ve HTTP istemcinizin nasıl çalışmasını istediğiniz hakkında daha fazla ayrıntı depolamak kolaydır. Daha fazla bilgi için bkz. Configuration in .NET.
Not
Kaynak tükenmesine neden olabileceğinden, kayıtlı ayrı adlandırılmış istemcilerin sayısı sınırsız olmamalıdır. Örneğin, istemci adını ilişkisiz girişten türetmayın.
İstemci oluşturma
Her seferinde CreateClient çağrılır:
- Yeni bir
HttpClientörneği oluşturuldu. - Yapılandırma eylemi çağrılır.
İsimlendirilmiş bir istemci oluşturmak için adını CreateClient içine geçirin.
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"];
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 [];
}
}
Yukarıdaki kodda HTTP isteğinin bir konak adı belirtmesi gerekmez. İstemci için yapılandırılan temel adres kullanıldığından kod yalnızca yolu geçirebilir.
Tip tanımlı istemciler
Tip belirli istemciler:
- Dizeleri anahtar olarak kullanmaya gerek kalmadan adlandırılmış istemcilerle aynı özellikleri sağlayın.
- İstemcileri kullanırken IntelliSense ve derleyici yardımı sağlayın.
- Belirli bir
HttpClientöğesini yapılandırmak ve etkileşime geçmek için tek bir konum sağlayın. Örneğin, tek bir türlenmiş istemci kullanılabilir:- Tek bir arka uç uçnoktası için.
- Uç noktayla ilgili tüm mantığı kapsüllemek için.
- Uygulamada gerektiğinde DI ile çalışabilir ve enjekte edilebilir.
Yazılan istemci, oluşturucusunda bir HttpClient parametreyi kabul eder:
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)
{
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 [];
}
}
Önceki kodda:
- Yazılan istemci hizmet koleksiyonuna eklendiğinde yapılandırma ayarlanır.
- ,
HttpClientsınıf kapsamlı değişken (alan) olarak atanır ve kullanıma sunulan API'lerle birlikte kullanılır.
İşlevselliği kullanıma sunan HttpClient API'ye özgü yöntemler oluşturulabilir. Örneğin, GetUserTodosAsync yöntemi, kullanıcıya özgü Todo nesnelerini almak için kodu kapsüller.
Aşağıdaki kod, türü yazılan bir istemci sınıfını kaydetmek için çağrı yapar AddHttpClient :
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");
});
Yazılan istemci, DI ile geçici olarak kaydedilir. Önceki kodda AddHttpClient, TodoService geçici bir hizmet olarak kaydedilir. Bu kayıt, aşağıdakiler için bir fabrika yöntemi kullanır:
-
HttpClientörneği oluşturun. -
TodoService'nin örneğini oluşturun veHttpClientörneğini yapıcıya geçirin.
Önemli
Tekli hizmetlerde yazılan istemcilerin kullanılması tehlikeli olabilir. Daha fazla bilgi için Tekli hizmetlerde Yazılan İstemcilerden Kaçınma bölümüne bakın.
Not
Türü belirtilen istemciyi AddHttpClient<TClient> yöntemiyle kaydederken, türün TClient parametre olarak kabul eden bir HttpClient oluşturucuya sahip olması gerekir. Buna ek olarak, TClient türün DI kapsayıcısına ayrı olarak kaydedilmemesi gerekir, çünkü bu daha sonra kaydın öncekinin üzerine yazılmasını sağlayacaktır.
Oluşturulan istemciler
IHttpClientFactory, Refit gibi üçüncü taraf kitaplıklarla birlikte kullanılabilir. Refit, .NET için bir REST kitaplığıdır. Bildirim temelli REST API tanımlarına, arabirim yöntemlerini uç noktalara eşlemeye olanak tanır. Arayüzün bir uygulaması, RestService tarafından dinamik olarak oluşturulur ve dış HTTP çağrılarını yapmak için HttpClient kullanılır.
Aşağıdaki record türü göz önünde bulundurun:
namespace Shared;
public record class Todo(
int UserId,
int Id,
string Title,
bool Completed);
Aşağıdaki örnek NuGet paketine Refit.HttpClientFactory dayanır ve basit bir arabirimdir:
using Refit;
using Shared;
namespace GeneratedHttp.Example;
public interface ITodoService
{
[Get("/todos?userId={userId}")]
Task<Todo[]> GetUserTodosAsync(int userId);
}
Yukarıdaki C# arabirimi:
-
GetUserTodosAsyncadlı birTask<Todo[]>örneği döndüren bir yöntem tanımlar. - Dış API'ye giden yolu ve sorgu dizesini içeren bir
Refit.GetAttributeöznitelik bildirir.
Uygulamayı oluşturmak için Refit kullanılarak türü oluşturulmuş bir istemci eklenebilir:
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 typed client.
client.BaseAddress = new Uri("https://jsonplaceholder.typicode.com/");
// Add a user-agent default request header.
client.DefaultRequestHeaders.UserAgent.ParseAdd("dotnet-docs");
});
Tanımlı arabirim, DI ve Refit tarafından sağlanan uygulamayla gerektiğinde kullanılabilir.
POST, PUT ve DELETE istekleri gönderme
Yukarıdaki örneklerde, tüm HTTP istekleri HTTP fiilini GET kullanır.
HttpClient ayrıca aşağıdakiler dahil olmak üzere diğer HTTP fiillerini de destekler:
POSTPUTDELETEPATCH
Desteklenen HTTP fiillerinin tam listesi için bkz HttpMethod. . HTTP istekleri oluşturma hakkında daha fazla bilgi için bkz . HttpClient kullanarak istek gönderme.
Aşağıdaki örnekte HTTP POST isteğinde bulunma gösterilmektedir:
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();
}
Yukarıdaki kodda CreateItemAsync yöntemi:
- parametresini
ItemkullanarakSystem.Text.JsonJSON'a serileştirir. Bu, serileştirme işlemini yapılandırmak için örneğini JsonSerializerOptions kullanır. - HTTP isteğinin gövdesinde göndermek üzere serileştirilmiş JSON'ı paketlemek için StringContent'ün bir örneğini oluşturur.
- Belirtilen URL'ye JSON içeriğini göndermek için PostAsync çağırır. Bu, HttpClient.BaseAddress'e eklenen göreli bir URL'dir.
- Yanıt durum kodu başarıyı göstermiyorsa özel durum oluşturma çağrısı EnsureSuccessStatusCode yapar.
HttpClient ayrıca diğer içerik türlerini de destekler. Örneğin, MultipartContent ve StreamContent. Desteklenen içeriğin tam listesi için bkz HttpContent. .
Aşağıdaki örnekte bir HTTP PUT isteği gösterilmektedir:
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();
}
Yukarıdaki kod örneğe POST çok benzer.
UpdateItemAsync yöntemi, PutAsync yerine PostAsync çağırır.
Aşağıdaki örnekte bir HTTP DELETE isteği gösterilmektedir:
public async Task DeleteItemAsync(Guid id)
{
using HttpResponseMessage httpResponse =
await httpClient.DeleteAsync($"/api/items/{id}");
httpResponse.EnsureSuccessStatusCode();
}
Önceki kodda DeleteItemAsync metodu DeleteAsync'i çağırır. HTTP DELETE istekleri genellikle içerik içermediğinden, DeleteAsync yöntemi, HttpContent örneğini kabul eden bir aşırı yükleme sağlamaz.
ile HttpClientfarklı HTTP fiilleri kullanma hakkında daha fazla bilgi edinmek için bkz HttpClient. .
HttpClient yaşam süresi yönetimi
Her HttpClient çağrıldığında CreateClient üzerinde yeni bir IHttpClientFactory örneği döndürülür.
HttpClientHandler İstemci adı başına bir örnek oluşturulur. Fabrika, HttpClientHandler örneklerinin ömürlerini yönetir.
IHttpClientFactory
HttpClientHandler kaynak tüketimini azaltmak için fabrika tarafından oluşturulan örnekleri önbelleğe alır.
HttpClientHandler Yaşam süresi dolmadıysa yeni HttpClient bir örnek oluşturulurken bir örnek önbellekten yeniden kullanılabilir.
her işleyici genellikle kendi temel HTTP bağlantı havuzunu yönettiğinden işleyicilerin önbelleğe alınmasını tercih edilir. Gerekenden daha fazla işleyici oluşturmak yuva tükenmesi ve 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.
Varsayılan işleyici ömrü iki dakikadır. Varsayılan değeri geçersiz kılmak için, SetHandlerLifetime içinde IHttpClientBuilder kaydederken her istemci için IHttpClientFactory üzerindeki ServiceCollection çağırın.
services.AddHttpClient("Named.Client")
.SetHandlerLifetime(TimeSpan.FromMinutes(5));
Önemli
HttpClienttarafından IHttpClientFactory oluşturulan örneklerin kısa ömürlü olması amaçlanmıştır.
İşleyicilerin DNS değişikliklerine tepki vermelerini sağlamak için
HttpMessageHandleryaşam süreleri dolduğunda bunları geri dönüştürmek ve yeniden oluşturmakIHttpClientFactoryçok önemlidir.HttpClientoluşturulurken belirli bir işleyici örneğine bağlıdır, bu nedenle istemcinin güncelleştirilmiş işleyiciyi edineceğinden emin olmak için yeniHttpClientörneklerin zamanında istenmesi gerekir.Fabrika tarafından oluşturulan bu tür
HttpClientörneklerin atılması, 'ün atılmasını tetiklemeyeceğinden, yuva tükenmesine yol açmaz.IHttpClientFactory,HttpClientörneklerini oluşturmak için kullanılan kaynakları izler ve bunları, özellikleHttpMessageHandlerörneklerinin kullanım ömrü sona erdiğinde ve artık onları kullananHttpClientkalmadığında, elden çıkarır.
Tek bir HttpClient örneği uzun süre canlı tutmak, yerine kullanılabilecek yaygın bir yoldur, ancak bu yol, IHttpClientFactory gibi ek kurulum gerektirir. Ya uzun ömürlü istemciler PooledConnectionLifetime kullanabilir ya da kısa ömürlü istemciler IHttpClientFactory tarafından oluşturulabilir. Uygulamanızda hangi stratejinin kullanılacağı hakkında bilgi için bkz . HTTP istemcilerini kullanma yönergeleri.
Yapılandırma: HttpMessageHandler
İstemci tarafından kullanılan iç HttpMessageHandler öğesinin yapılandırmasını denetlemek gerekebilir.
Adlandırılmış veya türü belirtilmiş istemciler eklenirken bir IHttpClientBuilder döndürülür.
ConfigurePrimaryHttpMessageHandler uzantı yöntemi üzerinde IHttpClientBuilder çağrılabilir ve bir temsilciye geçirilebilir. Temsilci, bu istemci tarafından kullanılan birincil HttpMessageHandler değeri oluşturmak ve yapılandırmak için kullanılır:
.ConfigurePrimaryHttpMessageHandler(() =>
{
return new HttpClientHandler
{
AllowAutoRedirect = false,
UseDefaultCredentials = true
};
});
HttpClientHandler işleyicisini yapılandırmak, örneğin HttpClient için bir proxy sunucu belirtmenize ve çeşitli diğer özellikleri ayarlamanıza olanak tanır. Daha fazla bilgi için bkz İstemci başına proxy.
Ek yapılandırma
'yi denetlemek IHttpClientBuilderiçin birkaç ek yapılandırma seçeneği vardır:
| Metot | Açıklama |
|---|---|
| AddHttpMessageHandler | Adı belirtilen HttpClient için ek bir mesaj işleyicisi ekler. |
| AddTypedClient |
TClient ile ilişkilendirilmiş olan HttpClient ve adlı IHttpClientBuilder arasındaki bağlamayı yapılandırıyor. |
| ConfigureHttpClient | adlı HttpClientbir yapılandırma için kullanılacak bir temsilci ekler. |
| ConfigurePrimaryHttpMessageHandler | Adlandırılmış bir HttpMessageHandler için bağımlılık ekleme kapsayıcısından birincil HttpClient'ı yapılandırır. |
| RedactLoggedHeaders | Günlüğe kaydedilmeden önce değerleri gizlenmesi gereken HTTP üst bilgi adları kümesini ayarlar. |
| SetHandlerLifetime | Bir HttpMessageHandler örneğin yeniden kullanılabilmesi için gereken süreyi ayarlar. Adlandırılmış her istemcinin kendi yapılandırılmış işleyici yaşam süresi değeri olabilir. |
| UseSocketsHttpHandler | Bağımlılık ekleme kapsayıcısından yeni veya daha önce eklenmiş SocketsHttpHandler örneğini, adlandırılmış bir HttpClient için birincil işleyici olarak kullanılacak şekilde yapılandırır. (yalnızca .NET 5+ ) |
IHttpClientFactory ve SocketsHttpHandler ile birlikte kullanma
SocketsHttpHandler uygulamasının HttpMessageHandler uygulaması, PooledConnectionLifetime yapılandırılmasını sağlayan .NET Core 2.1'e eklendi. Bu ayar, işleyicinin DNS değişikliklerine tepki vermesini sağlamak için kullanılır; bu nedenle kullanımı SocketsHttpHandler , kullanmaya IHttpClientFactoryalternatif olarak kabul edilir. Daha fazla bilgi için bkz . HTTP istemcilerini kullanma yönergeleri.
Ancak yapılandırılabilirliği SocketsHttpHandlerIHttpClientFactory geliştirmek için birlikte kullanılabilir. Bu API'lerin her ikisini de kullanarak, hem düşük düzeyde (örneğin, dinamik sertifika seçimi için kullanma LocalCertificateSelectionCallback ) hem de yüksek düzeyde yapılandırılabilirlikten (örneğin, DI tümleştirmesinden ve çeşitli istemci yapılandırmalarından yararlanma) yararlanabilirsiniz.
Her iki API'yi de kullanmak için:
-
SocketsHttpHandleröğesini ConfigurePrimaryHttpMessageHandler aracılığıylaPrimaryHandlerolarak veya UseSocketsHttpHandler olarak belirtin (yalnızca .NET 5+). - DNS'nin güncelleştirilmesini beklediğiniz aralığı temel alarak ayarlayın SocketsHttpHandler.PooledConnectionLifetime ; örneğin, daha önce uzantı yönteminde
SetHandlerLifetimeayarlanmış bir değere ayarlayın. - (İsteğe bağlı)
SocketsHttpHandlerbağlantı havuzunu ve geri dönüşüm yönetimini işleyeceğinden,IHttpClientFactorydüzeyinde işleyici geri dönüştürmeye artık gerek yoktur.HandlerLifetime'yıTimeout.InfiniteTimeSpanolarak ayarlayarak devre dışı bırakabilirsiniz.
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
Yukarıdaki örnekte, çizim amacıyla varsayılan HandlerLifetime değere hizalanmış şekilde rastgele 2 dakika seçilmiştir. Değeri, beklenen DNS sıklığına veya diğer ağ değişikliklerine göre seçmelisiniz. Daha fazla bilgi için yönergelerindeki HttpClient bölümüne ve PooledConnectionLifetime API belgelerindeki Açıklamalar bölümüne bakın.
Tekli servislerde tip tanımlı istemcilerden kaçının
Adlandırılmış istemci yaklaşımı kullanılırken, hizmetlere enjekte edilir ve her IHttpClientFactory gerektiğinde HttpClient çağrılarak CreateClient örnekleri oluşturulur.
Ancak, tipli istemci yaklaşımıyla, tipli istemciler genellikle hizmetlere enjekte edilen geçici nesnelerdir. Bu bir soruna neden olabilir çünkü türü belirtilen istemci tek bir hizmete eklenebilir.
Önemli
Yazılan istemcilerin, tarafından oluşturulan örneklerle aynı anlamda, HttpClient olmaları beklenir (daha fazla bilgi için bkz. IHttpClientFactory). Yazılan bir istemci örneği oluşturulur oluşturulmaz, IHttpClientFactory bunun üzerinde bir denetimi olmaz. Tip tanımlı bir istemci örneği bir singleton içinde yakalanırsa, DNS değişikliklerine tepki verme yeteneğini kaybedebilir ve IHttpClientFactory amaçlarından birini etkisiz hale getirebilir.
Singleton bir hizmette HttpClient örneklerini kullanmanız gerekiyorsa, aşağıdaki seçenekleri göz önünde bulundurun:
- Bunun yerine adlandırılmış istemci yaklaşımını kullanın, tekil hizmete ekleyin
IHttpClientFactoryve gerektiğinde örnekleri yeniden oluşturunHttpClient. - Tiplenmiş istemci yaklaşımını gerektiriyorsanız, birincil işleyici olarak yapılandırılmış ile
SocketsHttpHandlerkullanın.SocketsHttpHandlerveIHttpClientFactorybirlikte kullanımı hakkında daha fazla bilgi için SocketsHttpHandler ile IHttpClientFactory Kullanma bölümüne bakın.
İleti İşleyici Kapsamları içindeki IHttpClientFactory
IHttpClientFactory her HttpMessageHandler örnek için ayrı bir DI kapsamı oluşturur. Bu DI kapsamları, uygulama DI kapsamlarından (örneğin, ASP.NET gelen istek kapsamı veya kullanıcı tarafından oluşturulan elle bir DI kapsamı) bağımsızdır, bu nedenle kapsamlı hizmet örneklerini paylaşmayacaktır. İleti İşleyicisi kapsamları işleyici ömrüne bağlıdır ve uygulama kapsamlarının ötesine geçebilir. Bu durum, örneğin, birden çok gelen istek arasında aynı HttpMessageHandler örneğinin, aynı şekilde enjekte edilen kapsamlı bağımlılıklarla yeniden kullanılmasına yol açabilir.
Kullanıcıların, kapsamla ilgili bilgileri (örneğin, HttpContext'den gelen veriler) HttpMessageHandler örneklerinin içine önbelleğe almamaları ve duyarlı bilgilerin sızmasını önlemek için kapsamlı bağımlılıkları dikkatle kullanmaları şiddetle tavsiye edilir.
Örnek olarak kimlik doğrulaması için ileti işleyicinizden bir uygulama DI kapsamına erişmeniz gerekiyorsa, kapsam algılamalı mantığı ayrı bir geçici DelegatingHandleriçinde kapsüller ve önbellekteki HttpMessageHandler bir IHttpClientFactory örneğin çevresine sarmalarsınız. Kayıtlı herhangi bir IHttpMessageHandlerFactory.CreateHandler için işleyiciye erişmek üzere. Bu durumda, oluşturduğunuz işleyiciyi kullanarak kendiniz bir HttpClient örnek oluşturursunuz.
Aşağıdaki örnek, kapsamı algılayan bir HttpClient ile DelegatingHandler oluşturmayı göstermektedir.
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);
Alternatif bir çözüm olarak, kapsam bilincinde DelegatingHandler bir kaydın yapılması ve geçici bir hizmet aracılığıyla varsayılan IHttpClientFactory kaydının, geçerli uygulama kapsamına erişim sağlanarak, geçersiz kılınması için bir uzantı yöntemi kullanılabilir.
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;
}
Daha fazla bilgi için bkz . tam örnek.
"Fabrika ayarlarına sahip bir birincil işleyiciye bağımlı olmaktan kaçının"
Bu bölümde, "fabrika varsayılanı" Birincil İşleyicisi terimi, varsayılan IHttpClientFactory uygulamasının (veya daha doğrusu varsayılan HttpMessageHandlerBuilder uygulaması) herhangi bir şekilde yapılandırılmamışsa atadığı Birincil İşleyiciyi ifade eder.
Not
"Fabrika varsayılanı" Birincil İşleyici, bir uygulama ayrıntısıdır ve değiştirilebilir.
❌ Belirli bir uygulamanın "fabrika ayarları" olarak kullanılmasına bağımlı olmaktan KAÇININ (örneğin, HttpClientHandler).
Özellikle bir sınıf kitaplığı üzerinde çalışıyorsanız, bir Birincil İşleyicinin belirli türünü bilmeniz gereken durumlar vardır. Son kullanıcının yapılandırmasını korurken, örneğin HttpClientHandler, ClientCertificatesve UseCookiesgibi UseProxyözel özellikleri güncelleştirmek isteyebilirsiniz. Birincil işleyiciyi HttpClientHandler olarak atamak cazip gelebilir, ki bu, "fabrika varsayılanı" birincil işleyici olarak kullanılırken işe yaradı. Ancak uygulama ayrıntılarına bağlı olan herhangi bir kod gibi, bu tür bir geçici çözüm kırılgandır ve kırılma olasılığı yüksektir.
"Fabrika varsayılanı" Birincil İşleyicisi'ne güvenmek yerine, "uygulama düzeyi" varsayılan Birincil İşleyici örneğini ayarlamak için ConfigureHttpClientDefaults kullanabilirsiniz:
// 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) { ... }
});
Alternatif olarak, Birincil İşleyici türünü denetlemeyi ve istemci sertifikaları gibi özellikleri yalnızca iyi bilinen destekleyici türlerde (büyük olasılıkla HttpClientHandler ve SocketsHttpHandler) yapılandırabilirsiniz:
// --- "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) { ... }
});