.NET ile HTTP

Bu makalede bağımlılık ekleme (DI), günlüğe kaydetme ve yapılandırma gibi çeşitli .NET temel bilgileriyle ve türlerini IHttpClientFactory HttpClient kullanmayı öğrenirsiniz. Tür, HttpClient 2012'de .NET Framework 4.5'te tanıtıldı. Başka bir deyişle, bir süredir böyle. HttpClient , HTTP istekleri yapmak ve bir tarafından tanımlanan web kaynaklarından HTTP yanıtlarını işlemek için Uri kullanılır. HTTP protokolü, tüm internet trafiğinin büyük çoğunluğunu sağlar.

Modern uygulama geliştirme ilkeleri en iyi yöntemlerin yol gösterirken, özel yapılandırmalarla örnekler oluşturan IHttpClientFactory HttpClient bir fabrika soyutlama olarak görev almaktadır. IHttpClientFactory .NET Core 2.1'de tanıtıldı. Yaygın HTTP tabanlı .NET iş yükleri, kolay bir şekilde üçüncü taraf ara yazılımlara karşı, karşılarına çıkar ve geçici hata işlemeden faydalanabilirsiniz.

Türü IHttpClientFactory keşfetme

Bu makaledeki tüm örnek kaynak kodu, Microsoft.Extensions.Http NuGet. Buna ek olarak, "nerdy" için HTTP GET isteklerinde bulunduracak İnternetLide Norris Veritabanı ücretsiz API'si kullanılır.

Uzantı yöntemlerden herhangi AddHttpClient birini çağırarak ve ile ilgili hizmetlerini IHttpClientFactory 'ye eklersiniz. IServiceCollection Türü IHttpClientFactory aşağıdaki avantajları sunar:

  • Sınıfı HttpClient DI'ye hazır bir tür olarak kullanıma sağlar.
  • Mantıksal örnekleri adlandırmak ve yapılandırmak için merkezi bir HttpClient konum sağlar.
  • içinde işleyiciler için delete aracılığıyla giden ara yazılım kavramını HttpClient kodlar.
  • içinde işleyicileri seçme avantajını elde etmek için Polly tabanlı ara yazılım için uzantı yöntemleri HttpClient sağlar.
  • Temel alınan örneklerin havuzlarını ve yaşam HttpClientHandler sürelerini yönetir. Otomatik yönetim, yaşam sürelerini el ile yönetme sırasında oluşan yaygın Etki Alanı Adı Sistemi (DNS) HttpClient sorunlarını önler.
  • Fabrika tarafından oluşturulan istemciler aracılığıyla gönderilen tüm ILogger istekler için yapılandırılabilir bir günlük deneyimi (aracılığıyla) ekler.

Tüketim desenleri

Bir uygulamada çeşitli IHttpClientFactory yollarla kullanılabilir:

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

Temel kullanım

'i kaydetmek IHttpClientFactory için çağrısına AddHttpClient tıklayın:

using BasicHttp.Example;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging;

using IHost host = Host.CreateDefaultBuilder(args)
    .ConfigureServices(services =>
    {
        services.AddHttpClient();
        services.AddTransient<JokeService>();
    })
    .Build();

Hizmetleri kullanmak IHttpClientFactory için, DI ile oluşturucu parametresi olarak parametresini gerekli hale alabilir. Aşağıdaki kod bir IHttpClientFactory örnek oluşturmak için HttpClient kullanır:

using System.Net.Http.Json;
using Microsoft.Extensions.Logging;
using Shared;

namespace BasicHttp.Example;

public class JokeService
{
    private readonly IHttpClientFactory _httpClientFactory = null!;
    private readonly ILogger<JokeService> _logger = null!;

    public JokeService(
        IHttpClientFactory httpClientFactory,
        ILogger<JokeService> logger) =>
        (_httpClientFactory, _logger) = (httpClientFactory, logger);

    public async Task<string> GetRandomJokeAsync()
    {
        // Create the client
        HttpClient client = _httpClientFactory.CreateClient();

        try
        {
            // Make HTTP GET request
            // Parse JSON response deserialize into ChuckNorrisJoke type
            ChuckNorrisJoke? result = await client.GetFromJsonAsync<ChuckNorrisJoke>(
                "https://api.icndb.com/jokes/random?limitTo=[nerdy]",
                DefaultJsonSerialization.Options);

            if (result?.Value?.Joke is not null)
            {
                return result.Value.Joke;
            }
        }
        catch (Exception ex)
        {
            _logger.LogError("Error getting something fun to say: {Error}", ex);
        }

        return "Oops, something has gone wrong - that's not funny at all!";
    }
}

Yukarıdaki IHttpClientFactory örnekte olduğu gibi kullanmak, mevcut bir uygulamayı yeniden düzenlemenin iyi bir yolu olabilir. Bunun nasıl kullanıldıkları üzerinde HttpClient hiçbir etkisi yoktur. Örneklerin HttpClient var olan bir uygulamada oluşturulacak olduğu yerlerde, bu oluşumları çağrısıyla CreateClient değiştirin.

Adlandırılmış istemciler

Adlandırılmış istemciler şu zaman iyi bir seçimdir:

  • Uygulamanın birçok farklı kullanımı HttpClient gerekir.
  • Birçok HttpClient örneğin yapılandırması farklıdır.

adlı bir için HttpClient yapılandırma, içinde kayıt sırasında belirtilebilir: ConfigureServices

using NamedHttp.Example;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging;

using IHost host = Host.CreateDefaultBuilder(args)
    .ConfigureServices((context, services) =>
    {
        string httpClientName = context.Configuration["JokeHttpClientName"];
        services.AddHttpClient(
            httpClientName,
            client =>
            {
                // Set the base address of the named client.
                client.BaseAddress = new Uri("https://api.icndb.com/");

                // Add a user-agent default request header.
                client.DefaultRequestHeaders.UserAgent.ParseAdd("dotnet-docs");
            });
        services.AddTransient<JokeService>();
    })
    .Build();

Önceki kodda, istemci ile yapılandırılır:

  • altındaki yapılandırmadan çekilir bir "JokeHttpClientName" ad.
  • Temel https://api.icndb.com/ adres.
  • Üst "User-Agent" bilgi.

Http istemci adlarını belirtmek için yapılandırmayı kullanabilirsiniz; bu, ekleme ve oluşturmada istemcilerin yanlış adlarından kaçınmanıza yardımcı olur. Bu örnekte, HTTP istemci adını yapılandırmak için appsettings.json dosyası kullanılır:

{
    "JokeHttpClientName": "ChuckNorrisJokeApi"
}

Bu yapılandırmayı genişletmek ve HTTP istemcinizin nasıl çalışmasına ilişkin daha fazla ayrıntı depolamak kolaydır. Daha fazla bilgi için bkz. .NET'te yapılandırma.

İstemci oluşturma

Her zaman CreateClient çağrılır:

  • yeni bir HttpClient örneği oluşturulur.
  • Yapılandırma eylemi çağrılır.

Adlandırılmış bir istemci oluşturmak için adını içine CreateClient girin:

using System.Net.Http.Json;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.Logging;
using Shared;

namespace NamedHttp.Example;

public class JokeService
{
    private readonly IHttpClientFactory _httpClientFactory = null!;
    private readonly IConfiguration _configuration = null!;
    private readonly ILogger<JokeService> _logger = null!;

    public JokeService(
        IHttpClientFactory httpClientFactory,
        IConfiguration configuration,
        ILogger<JokeService> logger) =>
        (_httpClientFactory, _configuration, _logger) =
            (httpClientFactory, configuration, logger);

    public async Task<string> GetRandomJokeAsync()
    {
        // Create the client
        string httpClientName = _configuration["JokeHttpClientName"];
        HttpClient client = _httpClientFactory.CreateClient(httpClientName);

        try
        {
            // Make HTTP GET request
            // Parse JSON response deserialize into ChuckNorrisJoke type
            ChuckNorrisJoke? result = await client.GetFromJsonAsync<ChuckNorrisJoke>(
                "jokes/random?limitTo=[nerdy]",
                DefaultJsonSerialization.Options);

            if (result?.Value?.Joke is not null)
            {
                return result.Value.Joke;
            }
        }
        catch (Exception ex)
        {
            _logger.LogError("Error getting something fun to say: {Error}", ex);
        }

        return "Oops, something has gone wrong - that's not funny at all!";
    }
}

Yukarıdaki kodda HTTP isteğinin bir konak adı belirtmesi gerekm yok. İstemci için yapılandırılan temel adres kullanılırken kod yalnızca yolu geçebilirsiniz.

Türe bağlı istemciler

Türe bağlı istemciler:

  • Dizeleri anahtar olarak kullanmaya gerek kalmadan adlandırılmış istemcilerle aynı özellikleri sağlar.
  • İstemcileri tüketen IntelliSense ve derleyici yardımı sağlama.
  • Yapılandırmak ve belirli bir ile etkileşim kurmak için tek bir konum HttpClient sağlama. Örneğin, türü tek bir istemci kullanılabilir:
    • Tek bir arka uç uç noktası için.
    • Uç noktayla ilgili tüm mantığı kapsülleme.
  • DI ile çalışma ve uygulamaya gerektiğinde ekleme.

Türü türüne sahip bir istemci, HttpClient oluşturucusnda bir parametre kabul eder:

using System.Net.Http.Json;
using Microsoft.Extensions.Logging;
using Shared;

namespace TypedHttp.Example;

public sealed class JokeService
{
    private readonly HttpClient _httpClient = null!;
    private readonly ILogger<JokeService> _logger = null!;

    public JokeService(
        HttpClient httpClient,
        ILogger<JokeService> logger) =>
        (_httpClient, _logger) = (httpClient, logger);

    public async Task<string> GetRandomJokeAsync()
    {
        try
        {
            // Make HTTP GET request
            // Parse JSON response deserialize into ChuckNorrisJoke type
            ChuckNorrisJoke? result = await _httpClient.GetFromJsonAsync<ChuckNorrisJoke>(
                "https://api.icndb.com/jokes/random?limitTo=[nerdy]",
                DefaultJsonSerialization.Options);

            if (result?.Value?.Joke is not null)
            {
                return result.Value.Joke;
            }
        }
        catch (Exception ex)
        {
            _logger.LogError("Error getting something fun to say: {Error}", ex);
        }

        return "Oops, something has gone wrong - that's not funny at all!";
    }
}

Yukarıdaki kodda:

  • Türe sahip istemci hizmet koleksiyonuna ekleniyor olduğunda yapılandırma ayarlanır.
  • HttpClient, sınıf kapsamlı değişken (alan) olarak atanır ve açık API'lerle kullanılır.

İşlevselliği ortaya çıkaran API'ye özgü HttpClient yöntemler oluşturulabilir. Örneğin, GetRandomJokeAsync yöntemi rastgele bir rastgele almak için kodu kapsüller.

Aşağıdaki kod, türü AddHttpClient türü doğru olan bir istemci ConfigureServices sınıfını kaydetmek için çağrısında dır:

using TypedHttp.Example;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging;

using IHost host = Host.CreateDefaultBuilder(args)
    .ConfigureServices(services =>
    {
        services.AddHttpClient<JokeService>(
            client =>
            {
                // Set the base address of the named client.
                client.BaseAddress = new Uri("https://api.icndb.com/");

                // Add a user-agent default request header.
                client.DefaultRequestHeaders.UserAgent.ParseAdd("dotnet-docs");
            });
        services.AddTransient<JokeService>();
    })
    .Build();

Türe sahip istemci, DI ile geçici olarak kaydedilir. Yukarıdaki kodda, AddHttpClient geçici bir hizmet olarak JokeService kaydolr. Bu kayıt, aşağıdaki işlemleri yapmak için bir fabrika yöntemi kullanır:

  1. HttpClient örneği oluşturun.
  2. örneğini oluşturucuya JokeService geçirmesi için bir HttpClient örneği oluşturun.

İpucu

çağrısı AddHttpClient<TClient> hizmeti 'ye TClient IServiceCollection eklemez. Yine de ile açıkça eklemeniz Add{ServiceLifetime} gerekir.

Oluşturulan istemciler

IHttpClientFactory, Yeniden Sığdır gibi üçüncü taraf kitaplıklarla birlikte kullanılabilir. Yeniden sığdır, .NET için bir REST kitaplığıdır. Bildirimli tanımlamalar ve REST API arabirim yöntemlerini uç noktalara eşlemeye olanak sağlar. arabiriminin bir uygulaması, dış HTTP çağrıları yapmak RestService için kullanılarak dinamik olarak HttpClient oluşturulur.

Aşağıdaki türleri göz önünde record yapın:

namespace Shared;

public record IdentifiableJokeValue(
    int Id, string Joke);
namespace Shared;

public record ChuckNorrisJoke(
    string Type,
    IdentifiableJokeValue Value);

Aşağıdaki örnek, NuGet Refit.HttpClientFactory paketine dayandır ve basit bir arabirimdir:

using Refit;
using Shared;

namespace GeneratedHttp.Example;

public interface IJokeService
{
    [Get("/jokes/random?limitTo=[nerdy]")]
    Task<ChuckNorrisJoke> GetRandomJokeAsync();
}

Yukarıdaki C# arabirimi:

  • Bir örneği döndüren GetRandomJokeAsync adlı bir yöntemi Task<ChuckNorrisJoke> tanımlar.
  • Dış Refit.GetAttribute API'ye yol ve sorgu dizesi içeren bir öznitelik belirtir.

Türü oluşturulan bir istemci, uygulama oluşturmak için Yeniden Sığdır kullanılarak eklenebilir:

using GeneratedHttp.Example;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging;
using Refit;
using Shared;

using IHost host = Host.CreateDefaultBuilder(args)
    .ConfigureServices(services =>
    {
        services.AddRefitClient<IJokeService>()
            .ConfigureHttpClient(client =>
            {
                // Set the base address of the named client.
                client.BaseAddress = new Uri("https://api.icndb.com/");

                // Add a user-agent default request header.
                client.DefaultRequestHeaders.UserAgent.ParseAdd("dotnet-docs");
            });
    })
    .Build();

Tanımlanan arabirim gerektiğinde DI ve Refit tarafından sağlanan uygulamayla birlikte kullanılabilir.

POST, PUT ve DELETE istekleri yapma

Yukarıdaki örneklerde, tüm HTTP istekleri GET HTTP fiilini kullanır. HttpClient aşağıdakiler dahil olmak üzere diğer HTTP fiillerini de destekler:

  • POST
  • PUT
  • DELETE
  • YAMA

Desteklenen HTTP fiillerinin tam listesi için bkz. HttpMethod .

Aşağıdaki örnek, bir HTTP POST isteğinin nasıl yapılacağını göstermektedir:

public async Task CreateItemAsync(Item item)
{
    using StringContent json = new(
        JsonSerializer.Serialize(item, DefaultJsonSerialization.Options),
        Encoding.UTF8,
        MediaTypeNames.Application.Json);

    using HttpResponseMessage httpResponse =
        await _httpClient.PostAsync("/api/items", json);

    httpResponse.EnsureSuccessStatusCode();
}

Yukarıdaki kodda, CreateItemAsync yöntemi:

  • ItemParametresini kullanarak JSON için parametreyi seri hale getirir System.Text.Json . Bu JsonSerializerOptions , serileştirme işlemini yapılandırmak için bir örneğini kullanır.
  • StringContentHttp isteğinin gövdesinde göndermek üzere seri hale GETIRILMIŞ JSON paketini paketlemek için bir örneği oluşturur.
  • PostAsyncJSON içeriğini BELIRTILEN URL 'ye göndermek için çağrılar. Bu, HttpClient. BaseAddress'e eklenen GÖRELI bir URL 'dir.
  • EnsureSuccessStatusCodeYanıt durum kodu başarıyı belirtmezse bir özel durum oluşturmak için çağırır.

HttpClient , diğer içerik türlerini de destekler. Örneğin MultipartContent ve StreamContent. Desteklenen içeriğin tamamı 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, DefaultJsonSerialization.Options),
        Encoding.UTF8,
        MediaTypeNames.Application.Json);

    using HttpResponseMessage httpResponse =
        await _httpClient.PutAsync($"/api/items/{item.Id}", json);

    httpResponse.EnsureSuccessStatusCode();
}

Yukarıdaki kod, POST örneğine çok benzer. UpdateItemAsyncYöntemi yerine çağırır PutAsync PostAsync .

Aşağıdaki örnekte bir HTTP SILME isteği gösterilmektedir:

public async Task DeleteItemAsync(Guid id)
{
    using HttpResponseMessage httpResponse =
        await _httpClient.DeleteAsync($"/api/items/{id}");

    httpResponse.EnsureSuccessStatusCode();
}

Yukarıdaki kodda, DeleteItemAsync yöntemi çağırır DeleteAsync . HTTP DELETE istekleri genellikle gövde içermediğinden, DeleteAsync yöntemi bir örneğini kabul eden bir aşırı yükleme sağlamaz HttpContent .

İle farklı HTTP fiillerini kullanma hakkında daha fazla bilgi için HttpClient bkz HttpClient ..

HttpClient ömür yönetimi

HttpClientHer çağrıldığında yeni bir örnek döndürülür CreateClient IHttpClientFactory . HttpClientHandlerİstemci başına bir örnek oluşturulur. Fabrika, örneklerin yaşam sürelerini yönetir HttpClientHandler .

IHttpClientFactory``HttpClientHandlerkaynak tüketimini azaltmak için fabrika tarafından oluşturulan örnekleri havuzlar. Bir HttpClientHandler örnek, süresi dolmamışsa yeni bir örnek oluştururken havuzdan yeniden kullanılabilir HttpClient .

Her işleyici genellikle kendi temel aldığı HTTP bağlantısını yönettiğinden işleyicileri havuza alma işlemi tercih edilir. Gerekenden daha fazla işleyici oluşturulması bağlantı gecikmeleri oluşmasına neden olabilir. Ayrıca, bazı işleyiciler bağlantıları süresiz olarak açık tutar, bu da işleyicinin DNS değişikliklerine yeniden davranmasını engelleyebilir.

Varsayılan işleyici ömrü iki dakikadır. Varsayılan değeri geçersiz kılmak için, SetHandlerLifetime her istemci için çağrısı IServiceCollection :

services.AddHttpClient("Named.Client")
    .SetHandlerLifetime(TimeSpan.FromMinutes(5));

Önemli

Genellikle HttpClient örnekleri, elden çıkarma gerektirmeyen nesneler olarak değerlendirin. Çıkarma giden istekleri iptal eder ve HttpClient çağırma sonrasında verilen örneğin kullanılamaz olmasını sağlar Dispose . IHttpClientFactory örnekler tarafından kullanılan kaynakları izler ve ortadan kaldırdık HttpClient .

Tek HttpClient bir örneğinin uzun süre canlı tutulması, önünde kullanılmadan önce kullanılan ortak bir modeldir IHttpClientFactory . Bu model, ' a geçtikten sonra gereksiz hale gelir IHttpClientFactory .

Yapılandırma HttpMessageHandler

İstemci tarafından kullanılan iç yapılandırmayı denetlemek gerekli olabilir HttpMessageHandler .

IHttpClientBuilderAdlandırılmış veya yazılan istemciler eklenirken bir döndürülür. ConfigurePrimaryHttpMessageHandlerUzantı yöntemi, üzerinde bir temsilci tanımlamak için kullanılabilir IServiceCollection . Temsilci, HttpMessageHandler Bu istemci tarafından kullanılan birincili oluşturmak ve yapılandırmak için kullanılır:

services.AddHttpClient("Named.Client")
    .ConfigurePrimaryHttpMessageHandler(() =>
    {
        return new HttpClientHandler
        {
            AllowAutoRedirect = false,
            UseDefaultCredentials = true
        };
    });

Ek yapılandırma

' İ denetlemek için birkaç ek yapılandırma seçeneği vardır IHttpClientHandler :

Yöntem Açıklama
AddHttpMessageHandler Adlandırılmış için ek bir ileti işleyicisi ekler HttpClient .
AddTypedClient TClient HttpClient İle ilişkilendirilen ile ilişkili arasındaki bağlamayı yapılandırır IHttpClientBuilder .
ConfigureHttpClient Adlandırılmış bir adı yapılandırmak için kullanılacak bir temsilci ekler HttpClient .
ConfigureHttpMessageHandlerBuilder Adlandırılmış bir için kullanarak ileti işleyicilerini yapılandırmak için kullanılacak bir temsilci ekler HttpMessageHandlerBuilder HttpClient .
ConfigurePrimaryHttpMessageHandler HttpMessageHandlerAdlandırılmış için bağımlılık ekleme kapsayıcısından birincili yapılandırır HttpClient .
RedactLoggedHeaders Günlüğe kaydedilmeden önce değerlerin redaksiyonu gereken HTTP üst bilgi adları koleksiyonunu ayarlar.
SetHandlerLifetime Bir örneğin yeniden kullanılabilir olduğu sürenin uzunluğunu ayarlar HttpMessageHandler . Her bir adlandırılmış istemcinin kendi yapılandırılmış işleyici yaşam süresi değeri olabilir.

Ayrıca bkz.