.NET ile IHttpClientFactory
Bu makalede bağımlılık ekleme (DI), günlüğe kaydetme ve yapılandırma gibi çeşitli .NET temel bilgilerine sahip türler oluşturmak HttpClient
için 'yi kullanmayı IHttpClientFactory
öğreneceksiniz. Türü, HttpClient 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.
En iyi yöntemleri destekleyen modern uygulama geliştirme ilkeleriyle, IHttpClientFactory özel yapılandırmalarla örnekler oluşturabilen HttpClient
bir fabrika soyutlaması görevi görür. 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.
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.
Önemli
tarafından IHttpClientFactory
oluşturulan örneklerin HttpClient
yaşam süresi yönetimi, el ile oluşturulan örneklerden tamamen farklıdır. Stratejiler, tarafından IHttpClientFactory
oluşturulan kısa süreli istemcileri veya kurulumu olan PooledConnectionLifetime
uzun ömürlü istemcileri kullanmaktır. 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 makaledeki örnek kaynak kodunun tümü NuGet paketine Microsoft.Extensions.Http
dayanır. Ayrıca, kullanıcı Todo
nesnelerini almak için ücretsiz {JSON} Yer Tutucu API'sine HTTP GET
istekleri yapılır.
Uzantı yöntemlerinden herhangi birini AddHttpClient çağırdığınızda ve ilgili hizmetlerini öğesine IServiceCollectioneklersinizIHttpClientFactory
. Türü IHttpClientFactory
aşağıdaki avantajları sunar:
- sınıfını DI'ye
HttpClient
hazı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. - içindeki işleyicileri temsilci olarak atama yoluyla giden ara yazılım kavramını uyumlu hale getirir
HttpClient
. - içinde işleyicileri
HttpClient
temsilci seçme avantajından yararlanmak için Polly tabanlı ara yazılım için uzantı yöntemleri sağlar. - Temel HttpClientHandler alınan örneklerin önbelleğe alınmasını ve kullanım ömrünü yönetir. Otomatik yönetim, yaşam süreleri el ile yönetildiğinde
HttpClient
oluş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 yapılandırılabilir bir günlük deneyimi (aracılığıyla ILogger) ekler.
Tüketim desenleri
Bir uygulamada kullanılabilecek çeşitli yollar vardır IHttpClientFactory
:
- Temel kullanım
- Adlandırılmış istemciler
- Yazılan istemciler
- Adlandırılmış ve yazılan istemciler
- Oluşturulan istemciler
En iyi yaklaşım, uygulamanın gereksinimlerine bağlıdır.
Temel kullanım
öğesini kaydetmek için öğesini çağırınIHttpClientFactory
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();
Hizmetlerin tüketilmesi, DI ile oluşturucu parametresi olarak öğesini gerektirebilirIHttpClientFactory
. Aşağıdaki kod örnek HttpClient
oluşturmak için kullanırIHttpClientFactory
:
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 [];
}
}
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 örneklerin oluşturulduğu yerlerde HttpClient
, bu oluşumları çağrısıyla CreateClientdeğiştirin.
Adlandırılmış istemciler
Adlandırılmış istemciler şu durumlarda iyi bir seçimdir:
- Uygulama için birçok farklı kullanım
HttpClient
gerekir. - Birçok
HttpClient
örneğin farklı yapılandırmaları vardır.
Adlı bir ad HttpClient
için yapılandırma, üzerinde IServiceCollection
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:
- altındaki
"TodoHttpClientName"
yapılandırmadan çekilen bir ad. - temel adresi
https://jsonplaceholder.typicode.com/
. - Üst
"User-Agent"
bilgi.
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 . .NET'te yapılandırma.
İstemci oluşturma
Her seferinde CreateClient çağrılır:
- Yeni bir örneği
HttpClient
oluşturulur. - Yapılandırma eylemi çağrılır.
Adlandırılmış istemci oluşturmak için adını içine geçirin 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 [];
}
}
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.
Yazılan istemciler
Yazılan 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
HttpClient
bir öğesini yapılandırmak ve ile 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.
- DI ile çalışın ve uygulamada gerektiğinde eklenebilir.
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) : 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();
}
Önceki kodda:
- Yazılan istemci hizmet koleksiyonuna eklendiğinde yapılandırma ayarlanır.
- ,
HttpClient
sı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 yöntemi, GetUserTodosAsync
kullanıcıya özgü Todo
nesneleri 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 geçici AddHttpClient
bir hizmet olarak kaydeder TodoService
. Bu kayıt, aşağıdakiler için bir fabrika yöntemi kullanır:
HttpClient
örneği oluşturun.- örneğini
TodoService
oluşturucusunda geçirerek bir örneğiHttpClient
oluşturun.
Önemli
Tekli hizmetlerde yazılan istemcilerin kullanılması tehlikeli olabilir. Daha fazla bilgi için Tekli hizmetlerde Yazılan istemcilerden kaçınma bölümüne bakın.
Not
Türü belirtilen istemciyi AddHttpClient<TClient>
yöntemiyle kaydederken, türün TClient
parametre kabul eden bir HttpClient
oluşturucuya sahip olması gerekir. Buna ek olarak, TClient
türün DI kapsayıcısı ile ayrı olarak kaydedilmemesi gerekir.
Adlandırılmış ve yazılan istemciler
Adlandırılmış istemciler ve yazılan istemcilerin kendi güçlü ve zayıf yönleri vardır. Her iki dünyanın da en iyi şekilde yararlanmak için bu iki istemci türünü birleştirmenin bir yolu vardır.
Birincil kullanım örneği şunlardır: Aynı türemiş istemciyi farklı etki alanlarında kullanın. Örneğin, birincil ve ikincil bir hizmetiniz vardır ve bunlar tam olarak aynı işlevselliği sunar. Bu, istekleri vermek, yanıtları işlemek ve hataları işlemek üzere kullanımı sarmak HttpClient
için aynı türdeki istemciyi kullanabileceğiniz anlamına gelir. Aynı kod farklı yapılandırmalarla (örneğin, farklı temel adres, zaman aşımı ve kimlik bilgileri) kullanılır.
Aşağıdaki örnek, TodoService
yazılan istemciler bölümünde gösterilen aynı türe sahip istemciyi kullanır.
Önce adlandırılmış ve yazılan istemcileri kaydedin.
using Shared;
using TypedHttp.Example;
using Microsoft.Extensions.Http;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging;
HostApplicationBuilder builder = Host.CreateApplicationBuilder(args);
builder.Services.AddHttpClient<TodoService>("primary"
client =>
{
// Configure the primary typed client
client.BaseAddress = new Uri("https://primary-host-address.com/");
client.Timeout = TimeSpan.FromSeconds(3);
});
// Register the same typed client but with different settings
builder.Services.AddHttpClient<TodoService>("secondary"
client =>
{
// Configure the secondary typed client
client.BaseAddress = new Uri("https://secondary-host-address.com/");
client.Timeout = TimeSpan.FromSeconds(10);
});
Önceki kodda:
- İlk
AddHttpClient
çağrı, adı altında yazılan birTodoService
istemci kaydederprimary
. Temel alınanHttpClient
, birincil hizmete işaret etti ve kısa bir zaman aşımına sahip oldu. - İkinci
AddHttpClient
çağrı, adı altında yazılan birTodoService
istemci kaydedersecondary
. Temel alınanHttpClient
nokta ikincil hizmete işaret etti ve daha uzun bir zaman aşımına sahip.
using IHost host = builder.Build();
// Fetch an IHttpClientFactory instance to create a named client
IHttpClientFactory namedClientFactory =
host.Services.GetRequiredService<IHttpClientFactory>();
// Fetch an ITypedHttpClientFactory<TodoService> instance to create a named and typed client
ITypedHttpClientFactory<TodoService> typedClientFactory =
host.Services.GetRequiredService<ITypedHttpClientFactory<TodoService>>();
// Create a TodoService instance against the primary host
var primaryClient = namedClientFactory.CreateClient("primary");
var todoService = typedClientFactory.CreateClient(primaryClient);
Önceki kodda:
- Bir
IHttpClientFactory
örnek, yöntemi aracılığıylaCreateClient
adlandırılmış istemciler oluşturabilmek için DI kapsayıcısından alınır. ITypedHttpClientFactory<TodoService>
Di kapsayıcısından bir örnek, yöntemi aracılığıylaCreateClient
türlenmiş istemciler oluşturabilmek için alınır.- Bu
CreateClient
aşırı yükleme, parametresi olarak adlandırılmışHttpClient
bir (uygun yapılandırmaya sahip) aldı. - Oluşturulan
todoService
, birincil hizmeti kullanacak şekilde yapılandırılmıştır.
- Bu
Not
türü IHttpClientFactory
ad alanlarının System.Net.Http
içinde, ITypedHttpClientFactory
türü ise içinde Microsoft.Extensions.Http
yer alır.
Önemli
için tür parametresi ITypedHttpClientFactory
olarak uygulama sınıfını (önceki örnekte TodoService
olan ) kullanın. Soyutlamanız (arabirim gibi ITodoService
) olsa bile yine de uygulamayı kullanmanız gerekir. Soyutlama (ITodoService
) öğesini yanlışlıkla kullanırsanız, bunu çağırdığınızda CreateClient
bir InvalidOperationException
oluşturur.
try
{
Todo[] todos = await todoService.GetUserTodosAsync(4);
}
catch (TaskCanceledException ex) when (ex.InnerException is TimeoutException)
{
// The request timed out against the primary host
// Create a TodoService instance against the secondary host
var fallbackClient = namedClientFactory.CreateClient("secondary");
var todoFallbackService = typedClientFactory.CreateClient(fallbackClient);
// Issue request against the secondary host
Todo[] todos = await todoFallbackService.GetUserTodosAsync(4);
}
Önceki kodda:
- Birincil hizmete yönelik bir istek göndermeye çalışır.
- İstek zaman aşımına uğrarsa (3 saniyeden uzun sürerse
TaskCanceledException
) bir iç ile atarTimeoutException
. - Zaman aşımı durumunda, ikincil hizmeti hedefleyen yeni bir istemci oluşturulur ve kullanılır.
Oluşturulan istemciler
IHttpClientFactory
Yeniden Sığdır 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. Arabirimin bir uygulaması, dış HTTP çağrılarını yapmak için kullanılarak HttpClient
kullanılarak dinamik olarak RestService
oluşturulur.
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:
- Bir örnek döndüren adlı
GetUserTodosAsync
birTask<Todo[]>
yöntemi 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 named 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 yapma
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:
POST
PUT
DELETE
PATCH
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
Item
kullanarakSystem.Text.Json
JSON'a serileştirir. Bu, serileştirme işlemini yapılandırmak için örneğini JsonSerializerOptions kullanır. - HTTP isteğinin StringContent gövdesinde göndermek üzere serileştirilmiş JSON'ı paketlemek için bir örneği oluşturur.
- JSON içeriğini belirtilen URL'ye göndermek için çağrılar PostAsync . 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 yerine PostAsync
öğesini çağırırPutAsync.
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
yöntemi öğesini çağırır DeleteAsync. HTTP DELETE istekleri genellikle gövde içermediğinden, DeleteAsync
yöntemi bir örneğini HttpContent
kabul eden bir aşırı yükleme sağlamaz.
ile HttpClient
farklı HTTP fiilleri kullanma hakkında daha fazla bilgi edinmek için bkz HttpClient. .
HttpClient
yaşam süresi yönetimi
üzerinde IHttpClientFactory
her CreateClient
çağrıldığında yeni HttpClient
bir örnek döndürülür. HttpClientHandler İstemci adı başına bir örnek oluşturulur. Fabrika, örneklerin yaşam ömrünü HttpClientHandler
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 Alma 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, her istemci için öğesini üzerinde çağırın SetHandlerLifetimeIServiceCollection
:
services.AddHttpClient("Named.Client")
.SetHandlerLifetime(TimeSpan.FromMinutes(5));
Önemli
HttpClient
tarafı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
IHttpClientFactory
yaşam süreleri dolduğunda geri dönüşüm ve yeniden oluşturmaHttpMessageHandler
gereklidir.HttpClient
oluş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ı yuva tükenmesine yol açmaz, bunun atılması, 'nin atılmasıHttpMessageHandler
tetiklenmez.IHttpClientFactory
örnekleri oluşturmakHttpClient
için kullanılan kaynakları izler ve atar. ÖrneğinHttpMessageHandler
kullanım ömrü dolmaya başlar ve kullanım süresi dolmaz.HttpClient
Tek HttpClient
bir örneği uzun süre canlı tutmak, için alternatif IHttpClientFactory
olarak kullanılabilecek yaygın bir desendir, ancak bu desen gibi PooledConnectionLifetime
ek kurulum gerektirir. ile PooledConnectionLifetime
uzun ömürlü istemciler veya tarafından IHttpClientFactory
oluşturulan kısa süreli istemciler kullanabilirsiniz. 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.
IHttpClientBuilder adlandırılmış veya yazılan istemciler eklenirken bir döndürülür. ConfigurePrimaryHttpMessageHandler uzantı yöntemi üzerinde IServiceCollection
bir temsilci tanımlamak için kullanılabilir. 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
};
});
yapılandırması, HttClientHandler
işleyicinin HttpClient
diğer çeşitli özellikleri arasında örnek için bir ara sunucu belirtmenize olanak tanır. Daha fazla bilgi için bkz . İstemci başına ara sunucu.
Ek yapılandırma
'yi denetlemek IHttpClientHandler
için birkaç ek yapılandırma seçeneği vardır:
Metot | Açıklama |
---|---|
AddHttpMessageHandler | adlı HttpClient bir için ek bir ileti işleyicisi ekler. |
AddTypedClient | ile ilişkilendirilmiş ve adlı HttpClient arasındaki TClient bağlamayı yapılandırıyorIHttpClientBuilder . |
ConfigureHttpClient | adlı HttpClient bir yapılandırma için kullanılacak bir temsilci ekler. |
ConfigureHttpMessageHandlerBuilder | adlı HttpClient bir için kullanarak HttpMessageHandlerBuilder ileti işleyicilerini yapılandırmak için kullanılacak bir temsilci ekler. |
ConfigurePrimaryHttpMessageHandler | Adlı HttpClient bir için bağımlılık ekleme kapsayıcısından birincil HttpMessageHandler öğesini yapılandırır. |
RedactLoggedHeaders | Günlüğe kaydetmeden önce değerlerin yeniden işlemden geçmesi gereken HTTP üst bilgi adları koleksiyonunu 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. |
IHttpClientFactory'i Yuvalarla Birlikte KullanmaHttpHandler
SocketsHttpHandler
uygulamasıHttpMessageHandler
, yapılandırılmasına izin veren PooledConnectionLifetime
.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 IHttpClientFactory
alternatif olarak kabul edilir. Daha fazla bilgi için bkz . HTTP istemcilerini kullanma yönergeleri.
Ancak ve SocketsHttpHandler
IHttpClientFactory
birlikte kullanılabilir, yapılandırılabilirliği geliştirir. 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:
- olarak
PrimaryHandler
belirtinSocketsHttpHandler
ve değeriniPooledConnectionLifetime
ayarlayın (örneğin, daha önce içindeHandlerLifetime
olan bir değere). - Bağlantı
SocketsHttpHandler
havuzu oluşturma ve geri dönüştürme işlemlerinin yanı sıra, düzeyinde işleyici geri dönüşümüneIHttpClientFactory
artık ihtiyaç duyulmaz. olarak ayarlayarakHandlerLifetime
Timeout.InfiniteTimeSpan
devre dışı bırakabilirsiniz.
services.AddHttpClient(name)
.ConfigurePrimaryHttpMessageHandler(() =>
{
return new SocketsHttpHandler()
{
PooledConnectionLifetime = TimeSpan.FromMinutes(2)
};
})
.SetHandlerLifetime(Timeout.InfiniteTimeSpan); // Disable rotation, as it is handled by PooledConnectionLifetime
Tekli hizmetlerde yazılan istemcilerden kaçının
Adlandırılmış istemci yaklaşımı kullanılırken hizmetlere IHttpClientFactory
eklenir ve HttpClient
her gerektiğinde çağrılarak CreateClientHttpClient
örnekler oluşturulur.
Ancak, yazılan istemci yaklaşımıyla, yazılan istemciler genellikle hizmetlere eklenen geçici nesnelerdir. Bu bir soruna neden olabilir çünkü türü belirtilen istemci tek bir hizmete eklenebilir.
Önemli
Yazılan istemcilerin, tarafından IHttpClientFactory
oluşturulan örneklerle aynı anlamda HttpClient
kısa ömürlü olması beklenir (daha fazla bilgi için bkzHttpClient
. yaşam süresi yönetimi). Yazılan bir istemci örneği oluşturulur oluşturulmaz, IHttpClientFactory
bunun üzerinde bir denetimi olmaz. Yazılan bir istemci örneği tekil olarak yakalanırsa, DNS değişikliklerine tepki vermesini engelleyebilir ve amaçlarından IHttpClientFactory
birini yenebilir.
Tek bir hizmette örnekleri kullanmanız HttpClient
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
IHttpClientFactory
ve gerektiğinde örnekleri yeniden oluşturunHttpClient
. - Yazılan istemci yaklaşımına ihtiyacınız varsa, birincil işleyici olarak yapılandırılmış
PooledConnectionLifetime
ile kullanınSocketsHttpHandler
. ile kullanmaSocketsHttpHandler
IHttpClientFactory
hakkında daha fazla bilgi için Yuvalarla Birlikte IHttpClientFactory KullanmaHttpHandler bölümüne bakın.
IHttpClientFactory'de İleti İşleyici kapsamları
IHttpClientFactory
her HttpMessageHandler
örnek için ayrı bir DI kapsamı oluşturur. Bu DI kapsamları, uygulama DI kapsamlarından (örneğin, gelen istek kapsamı ASP.NET veya kullanıcı tarafından oluşturulan el ile oluşturulmuş bir DI kapsamı) ayrıdır, bu nedenle kapsamlı hizmet örneklerini paylaşmaz. İleti İşleyicisi kapsamları işleyici ömrüne bağlıdır ve uygulama kapsamlarından daha uzun sürebilir ve bu da örneğin aynı örneği birden fazla gelen istek arasında aynı eklenen kapsamlı bağımlılıklarla yeniden kullanmaya HttpMessageHandler
neden olabilir.
Kullanıcıların, kapsamla ilgili bilgileri (örneğin, içindeki verileriHttpContext
) örneklerin içinde HttpMessageHandler
önbelleğe almamaları ve hassas bilgilerin sızmasını önlemek için kapsamlı bağımlılıkları dikkatli kullanmamaları önemle önerilir.
Ö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 DelegatingHandler
içinde kapsüller ve önbellekteki IHttpClientFactory
bir HttpMessageHandler
örneğin çevresine sarmalarsınız. Kayıtlı adlandırılmış herhangi bir istemcinin işleyici çağrısına IHttpMessageHandlerFactory.CreateHandler erişmek için. Bu durumda, oluşturduğunuz işleyiciyi kullanarak kendiniz bir HttpClient
örnek oluşturursunuz.
Aşağıdaki örnekte, kapsamı algılayan DelegatingHandler
bir ile oluşturma HttpClient
gösterilmektedir:
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);
Kapsam kullanan DelegatingHandler
bir kaydı kaydetmek ve geçerli uygulama kapsamına erişimi olan geçici bir hizmet tarafından varsayılan IHttpClientFactory
kaydı geçersiz kılmaya yönelik bir uzantı yöntemiyle daha fazla geçici çözüm 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.
Ayrıca bkz.
Geri Bildirim
https://aka.ms/ContentUserFeedback.
Çok yakında: 2024 boyunca, içerik için geri bildirim mekanizması olarak GitHub Sorunları’nı kullanımdan kaldıracak ve yeni bir geri bildirim sistemiyle değiştireceğiz. Daha fazla bilgi için bkz.Gönderin ve geri bildirimi görüntüleyin