Aracılığıyla paylaş


.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 IHttpClientFactory için arabirimi kullanmayı HttpClient öğ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 HttpClient oluşturulan örneklerin IHttpClientFactory yaşam süresi yönetimi, el ile oluşturulan örneklerden tamamen farklıdır. Stratejiler, tarafından oluşturulan kısa süreliPooledConnectionLifetime. 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 ücretsiz GET API'sinden kullanıcı Todo nesnelerini almak için HTTP isteklerinin kullanımını gösterir.

Uzantı yöntemlerinden herhangi birini AddHttpClient çağırdığınızda ve ilgili hizmetlerini öğesine IHttpClientFactoryeklersinizIServiceCollection. 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 HttpClienttemsilci 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 :

En iyi yaklaşım, uygulamanın gereksinimlerine bağlıdır.

Temel kullanım

öğesini kaydetmek için öğesini çağırınIHttpClientFactoryAddHttpClient:

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, DIIHttpClientFactoryoluşturucu parametresi olarak öğesini gerektirebilir. Aşağıdaki kod örnek IHttpClientFactory oluşturmak için kullanırHttpClient:

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 HttpClientgerekir.
  • Birçok HttpClient örneğin farklı yapılandırmaları vardır.

Adlı bir ad HttpClient için yapılandırma, üzerinde IServiceCollectionkayı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 HttpClientbir öğ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:

  1. HttpClient örneği oluşturun.
  2. örneğini TodoServiceoluşturucusunda geçirerek bir örneği HttpClient 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 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

IHttpClientFactoryYeniden 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 RestService kullanılarak dinamik olarak HttpClientoluş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 bir Task<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 kullanarak System.Text.JsonJSON'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 PutAsyncöğesini çağırırPostAsync.

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 HttpContentkabul 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

üzerinde HttpClienther CreateClient çağrıldığında yeni IHttpClientFactory 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 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, her istemci için öğesini üzerinde çağırın SetHandlerLifetimeIServiceCollection:

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 HttpMessageHandler yaşam süreleri dolduğunda geri dönüşüm ve yeniden oluşturma IHttpClientFactorygereklidir. 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 yeni HttpClient ö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ıHttpMessageHandler. IHttpClientFactoryörnekleri oluşturmak HttpClient için kullanılan kaynakları izler ve atar. Örneğin HttpMessageHandler 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 IHttpClientFactorydesendir, ancak bu desen gibi PooledConnectionLifetimeek kurulum gerektirir. ile uzun ömürlüIHttpClientFactory. 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 IServiceCollectionbir 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 IHttpClientHandleriçin birkaç ek yapılandırma seçeneği vardır:

Metot Açıklama
AddHttpMessageHandler adlı HttpClientbir için ek bir ileti işleyicisi ekler.
AddTypedClient ile ilişkilendirilmiş ve adlı TClient arasındaki HttpClient bağlamayı yapılandırıyorIHttpClientBuilder.
ConfigureHttpClient adlı HttpClientbir yapılandırma için kullanılacak bir temsilci ekler.
ConfigurePrimaryHttpMessageHandler Adlı HttpMessageHandlerbir için bağımlılık ekleme kapsayıcısından birincil HttpClient öğ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.
UseSocketsHttpHandler Bağımlılık ekleme kapsayıcısından yeni veya daha önce eklenmiş SocketsHttpHandler bir örneği, adlandırılmış HttpClientbir için birincil işleyici olarak kullanılacak şekilde yapılandırır. (yalnızca.NET 5+ )

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 IHttpClientFactoryalternatif olarak kabul edilir. Daha fazla bilgi için bkz . HTTP istemcilerini kullanma yönergeleri.

Ancak ve SocketsHttpHandlerIHttpClientFactory 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:

  1. veya (yalnızca.NET 5+ ile) olarak SocketsHttpHandlerPrimaryHandlerConfigurePrimaryHttpMessageHandler belirtin.UseSocketsHttpHandler
  2. DNS'nin güncelleştirilmesini beklediğiniz aralığı temel alarak ayarlayın SocketsHttpHandler.PooledConnectionLifetime ; örneğin, daha önce içinde HandlerLifetimeolan bir değere ayarlayın.
  3. (İsteğe bağlı) SocketsHttpHandler Bağlantı havuzunu ve geri dönüşümü işleyeceğinden, düzeyinde işleyici geri dönüşümüne IHttpClientFactory artık gerek yoktur. olarak ayarlayarak HandlerLifetimeTimeout.InfiniteTimeSpandevre 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önergelerdeki HttpClient bölümüne ve API belgelerindeki PooledConnectionLifetime Açıklamalar bölümüne bakın.

Tekli hizmetlerde yazılan istemcilerden kaçının

Adlandırılmış istemci yaklaşımı kullanılırken HttpClient

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 oluşturulan örneklerle aynı anlamda HttpClient kısa ömürlüIHttpClientFactorybeklenir (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 IHttpClientFactorybirini 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 PooledConnectionLifetime ile kullanma SocketsHttpHandlerIHttpClientFactoryhakkı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.

İki uygulama DI kapsamını ve ayrı bir ileti işleyici kapsamını gösteren diyagram

Kullanıcıların, kapsamla ilgili bilgileriHttpMessageHandler.

Ö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ı IHttpMessageHandlerFactory.CreateHandler işleyici çağrısına erişmek için. Bu durumda, oluşturduğunuz işleyiciyi kullanarak kendiniz bir HttpClient örnek oluşturursunuz.

Ayrı bir geçici ileti işleyicisi ve IHttpMessageHandlerFactory aracılığıyla uygulama DI kapsamlarına erişim kazanmayı gösteren diyagram

Aşağıdaki örnekte, kapsamı algılayan HttpClientbir ile oluşturma DelegatingHandler 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.

"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 ClientCertificates, UseCookiesve UseProxygibi HttpClientHandlerözel özellikleri güncelleştirmek isteyebilirsiniz. Birincil işleyiciyi HttpClientHandlerolarak atamayı , HttpClientHandler "fabrika varsayılanı" Birincil İşleyicisi olarak kullanılırken iş başına geldi. Ancak uygulama ayrıntılarına bağlı olarak herhangi bir kod gibi, bu tür bir geçici çözüm kırılgan ve kırılmaya bağlıdır.

"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) { ... }
    });

Ayrıca bkz.