ASP.NET Core 'de ıhttpclientfactory kullanarak HTTP istekleri yapın
Kirk Larkabağı, Steve Gordon, Glenn CONDRONve Ryan şimdi ak.
Bir IHttpClientFactory uygulamadaki örnekleri yapılandırmak ve oluşturmak için kayıt yapılabilir ve kullanılabilir HttpClient . IHttpClientFactory aşağıdaki avantajları sunar:
- , Mantıksal örnekleri adlandırmak ve yapılandırmak için merkezi bir konum sağlar
HttpClient. Örneğin, GitHub adlı bir istemci, GitHuberişmek için kaydedilebilir ve yapılandırılabilir. Varsayılan istemci, genel erişim için kaydedilebilir. - ' De işleyiciler temsilci seçme yoluyla giden ara yazılım kavramını daha da artırır
HttpClient. ' De işleyiciler temsilci atama avantajlarından faydalanmak için, Polya tabanlı bir ara yazılım için uzantılar sağlarHttpClient. - Temel örneklerin biriktirmesini ve ömrünü yönetir
HttpClientMessageHandler. Otomatik yönetim, yaşam sürelerini el ile yönetirken oluşan ortak DNS (etki alanı adı sistemi) sorunlarını önlerHttpClient. ILoggerFabrika tarafından oluşturulan istemciler aracılığıyla gönderilen tüm istekler için yapılandırılabilir bir günlüğe kaydetme deneyimi ekler (aracılığıyla).
Örnek kodu görüntüleyin veya indirin (nasıl indirilir).
Bu konu sürümündeki örnek kod, System.Text.Json http yanıtlarında döndürülen JSON içeriğinin serisini kaldırmak için kullanır. Ve kullanan örnekler için Json.NET ReadAsAsync<T> , bu konunun 2. x sürümünü seçmek üzere sürüm seçiciyi kullanın.
Tüketim desenleri
Bir uygulamada çeşitli yollar IHttpClientFactory kullanılabilir:
En iyi yaklaşım, uygulamanın gereksinimlerine bağlı olarak değişir.
Temel kullanım
IHttpClientFactory , çağırarak kaydedilebilir AddHttpClient :
public class Startup
{
public Startup(IConfiguration configuration)
{
Configuration = configuration;
}
public IConfiguration Configuration { get; }
public void ConfigureServices(IServiceCollection services)
{
services.AddHttpClient();
// Remaining code deleted for brevity.
IHttpClientFactory Bağımlılık ekleme (dı)kullanılarak bir istek yapılabilir. Aşağıdaki kod IHttpClientFactory bir örnek oluşturmak için kullanır HttpClient :
public class BasicUsageModel : PageModel
{
private readonly IHttpClientFactory _clientFactory;
public IEnumerable<GitHubBranch> Branches { get; private set; }
public bool GetBranchesError { get; private set; }
public BasicUsageModel(IHttpClientFactory clientFactory)
{
_clientFactory = clientFactory;
}
public async Task OnGet()
{
var request = new HttpRequestMessage(HttpMethod.Get,
"https://api.github.com/repos/dotnet/AspNetCore.Docs/branches");
request.Headers.Add("Accept", "application/vnd.github.v3+json");
request.Headers.Add("User-Agent", "HttpClientFactory-Sample");
var client = _clientFactory.CreateClient();
var response = await client.SendAsync(request);
if (response.IsSuccessStatusCode)
{
using var responseStream = await response.Content.ReadAsStreamAsync();
Branches = await JsonSerializer.DeserializeAsync
<IEnumerable<GitHubBranch>>(responseStream);
}
else
{
GetBranchesError = true;
Branches = Array.Empty<GitHubBranch>();
}
}
}
IHttpClientFactoryYukarıdaki örnekte olduğu gibi kullanmak, mevcut bir uygulamayı yeniden düzenleme için iyi bir yoldur. Kullanım hakkında hiçbir etkisi yoktur HttpClient . HttpClientVar olan bir uygulamada örneklerin oluşturulduğu yerlerde, bu oluşumların ' i çağrılarıyla değiştirin CreateClient .
Adlandırılmış istemciler
Adlandırılmış istemciler şu durumlarda iyi bir seçimdir:
- Uygulama birçok farklı kullanımı gerektirir
HttpClient. - Birçok
HttpClients farklı yapılandırmaya sahiptir.
Adlandırılmış için yapılandırma HttpClient , içinde kayıt sırasında belirtilebilir Startup.ConfigureServices :
services.AddHttpClient("github", c =>
{
c.BaseAddress = new Uri("https://api.github.com/");
// Github API versioning
c.DefaultRequestHeaders.Add("Accept", "application/vnd.github.v3+json");
// Github requires a user-agent
c.DefaultRequestHeaders.Add("User-Agent", "HttpClientFactory-Sample");
});
İstemcinin yapılandırıldığı önceki kodda:
- Temel adres
https://api.github.com/. - GitHub apı ile çalışmak için iki üst bilgi gereklidir.
CreateClient
Her zaman CreateClient çağrılır:
- Yeni bir örneği
HttpClientoluşturulur. - Yapılandırma eylemi çağrılır.
Adlandırılmış bir istemci oluşturmak için adını içine geçirin CreateClient :
public class NamedClientModel : PageModel
{
private readonly IHttpClientFactory _clientFactory;
public IEnumerable<GitHubPullRequest> PullRequests { get; private set; }
public bool GetPullRequestsError { get; private set; }
public bool HasPullRequests => PullRequests.Any();
public NamedClientModel(IHttpClientFactory clientFactory)
{
_clientFactory = clientFactory;
}
public async Task OnGet()
{
var request = new HttpRequestMessage(HttpMethod.Get,
"repos/dotnet/AspNetCore.Docs/pulls");
var client = _clientFactory.CreateClient("github");
var response = await client.SendAsync(request);
if (response.IsSuccessStatusCode)
{
using var responseStream = await response.Content.ReadAsStreamAsync();
PullRequests = await JsonSerializer.DeserializeAsync
<IEnumerable<GitHubPullRequest>>(responseStream);
}
else
{
GetPullRequestsError = true;
PullRequests = Array.Empty<GitHubPullRequest>();
}
}
}
Yukarıdaki kodda, isteğin bir ana bilgisayar adı belirtmesi gerekmez. İstemci için yapılandırılan taban adresi kullanıldığından, kod yalnızca yolu geçirebilir.
Yazılan istemciler
Yazılan istemciler:
- Dizeleri anahtar olarak kullanma gereksinimi olmadan, adlandırılmış istemcilerle aynı özellikleri sağlayın.
- İstemcileri tükettiren IntelliSense ve derleyici yardımı sağlar.
- Yapılandırmak ve belirli bir ile etkileşimde bulunmak için tek bir konum belirtin
HttpClient. Örneğin, tek bir türü belirtilmiş istemci kullanılabilir:- Tek bir arka uç uç noktası için.
- Uç nokta ile ilgili tüm mantığı kapsüllemek için.
- DI ile birlikte çalışın ve uygulamada gerektiğinde eklenebilir.
Türü belirtilmiş istemci HttpClient , oluşturucusunda bir parametreyi kabul eder:
public class GitHubService
{
public HttpClient Client { get; }
public GitHubService(HttpClient client)
{
client.BaseAddress = new Uri("https://api.github.com/");
// GitHub API versioning
client.DefaultRequestHeaders.Add("Accept",
"application/vnd.github.v3+json");
// GitHub requires a user-agent
client.DefaultRequestHeaders.Add("User-Agent",
"HttpClientFactory-Sample");
Client = client;
}
public async Task<IEnumerable<GitHubIssue>> GetAspNetDocsIssues()
{
return await Client.GetFromJsonAsync<IEnumerable<GitHubIssue>>(
"/repos/aspnet/AspNetCore.Docs/issues?state=open&sort=created&direction=desc");
}
}
Yukarıdaki kodda:
- Yapılandırma, yazılan istemciye taşınır.
HttpClientNesne bir ortak özellik olarak sunulur.
İşlevselliği kullanıma sunan, API 'ye özgü Yöntemler oluşturulabilir HttpClient . Örneğin, GetAspNetDocsIssues yöntemi açık sorunları almak için kodu kapsüller.
Aşağıdaki kod, AddHttpClient Startup.ConfigureServices türü belirtilmiş bir istemci sınıfını kaydetmek için ' de çağırır:
services.AddHttpClient<GitHubService>();
Yazılan istemci, DI ile geçici olarak kaydedilir. Yukarıdaki kodda AddHttpClient GitHubService geçici bir hizmet olarak kaydedilir. Bu kayıt, için bir fabrika yöntemi kullanır:
HttpClientörneği oluşturun.- Örneğini oluşturucusuna geçirerek bir örneğini oluşturun
GitHubServiceHttpClient.
Yazılan istemci doğrudan eklenebilir ve tüketilebilir:
public class TypedClientModel : PageModel
{
private readonly GitHubService _gitHubService;
public IEnumerable<GitHubIssue> LatestIssues { get; private set; }
public bool HasIssue => LatestIssues.Any();
public bool GetIssuesError { get; private set; }
public TypedClientModel(GitHubService gitHubService)
{
_gitHubService = gitHubService;
}
public async Task OnGet()
{
try
{
LatestIssues = await _gitHubService.GetAspNetDocsIssues();
}
catch(HttpRequestException)
{
GetIssuesError = true;
LatestIssues = Array.Empty<GitHubIssue>();
}
}
}
Türü belirtilmiş bir istemcinin yapılandırması Startup.ConfigureServices , türü belirlenmiş istemcinin Oluşturucusu yerine kayıt sırasında belirtilebilir:
services.AddHttpClient<RepoService>(c =>
{
c.BaseAddress = new Uri("https://api.github.com/");
c.DefaultRequestHeaders.Add("Accept", "application/vnd.github.v3+json");
c.DefaultRequestHeaders.Add("User-Agent", "HttpClientFactory-Sample");
});
, HttpClient Türü belirlenmiş bir istemci içinde kapsüllenebilir. Bunu bir özellik olarak göstermek yerine, örneği dahili olarak çağıran bir yöntem tanımlayın HttpClient :
public class RepoService
{
// _httpClient isn't exposed publicly
private readonly HttpClient _httpClient;
public RepoService(HttpClient client)
{
_httpClient = client;
}
public async Task<IEnumerable<string>> GetRepos()
{
var response = await _httpClient.GetAsync("aspnet/repos");
response.EnsureSuccessStatusCode();
using var responseStream = await response.Content.ReadAsStreamAsync();
return await JsonSerializer.DeserializeAsync
<IEnumerable<string>>(responseStream);
}
}
Yukarıdaki kodda, HttpClient bir özel alanda depolanır. Öğesine erişimi, HttpClient genel yöntemi tarafından yapılır GetRepos .
Oluşturulan istemciler
IHttpClientFactory , yeniden sığdırmagibi üçüncü taraf kitaplıklarla birlikte kullanılabilir. Yeniden sığdırma, .NET için bir REST kitaplığıdır. REST API 'Leri canlı arabirimlere dönüştürür. Arabirim bir uygulama, RestService HttpClient dış http çağrıları yapmak için kullanılarak tarafından dinamik olarak oluşturulur.
Bir arabirim ve yanıt, dış API 'yi ve yanıtını temsil edecek şekilde tanımlanır:
public interface IHelloClient
{
[Get("/helloworld")]
Task<Reply> GetMessageAsync();
}
public class Reply
{
public string Message { get; set; }
}
Türü belirlenmiş bir istemci eklenebilir, uygulamayı oluşturmak için yeniden sığdırma kullanımı kullanılabilir:
public void ConfigureServices(IServiceCollection services)
{
services.AddHttpClient("hello", c =>
{
c.BaseAddress = new Uri("http://localhost:5000");
})
.AddTypedClient(c => Refit.RestService.For<IHelloClient>(c));
services.AddControllers();
}
Tanımlı arabirim, gereken yerde, mak ve Refit tarafından sağlanmış uygulama ile kullanılabilir.
[ApiController]
public class ValuesController : ControllerBase
{
private readonly IHelloClient _client;
public ValuesController(IHelloClient client)
{
_client = client;
}
[HttpGet("/")]
public async Task<ActionResult<Reply>> Index()
{
return await _client.GetMessageAsync();
}
}
GÖNDERI, PUT ve DELETE isteklerini oluşturma
Yukarıdaki örneklerde, tüm HTTP istekleri GET HTTP fiilini kullanır. HttpClient , aşağıdakiler de dahil olmak üzere diğer HTTP fiillerini de destekler:
- POST
- PUT
- DELETE
- DÜZELTMESI
Desteklenen HTTP fiillerinin tüm 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(TodoItem todoItem)
{
var todoItemJson = new StringContent(
JsonSerializer.Serialize(todoItem, _jsonSerializerOptions),
Encoding.UTF8,
"application/json");
using var httpResponse =
await _httpClient.PostAsync("/api/TodoItems", todoItemJson);
httpResponse.EnsureSuccessStatusCode();
}
Yukarıdaki kodda, CreateItemAsync yöntemi:
TodoItemParametresini kullanarak JSON için parametreyi seri hale getirirSystem.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österir:
public async Task SaveItemAsync(TodoItem todoItem)
{
var todoItemJson = new StringContent(
JsonSerializer.Serialize(todoItem),
Encoding.UTF8,
"application/json");
using var httpResponse =
await _httpClient.PutAsync($"/api/TodoItems/{todoItem.Id}", todoItemJson);
httpResponse.EnsureSuccessStatusCode();
}
Yukarıdaki kod, POST örneğine çok benzer. yöntemi SaveItemAsync yerine PutAsync yöntemini PostAsync çağıran.
Aşağıdaki örnekte bir HTTP DELETE isteği gösterir:
public async Task DeleteItemAsync(long itemId)
{
using var httpResponse =
await _httpClient.DeleteAsync($"/api/TodoItems/{itemId}");
httpResponse.EnsureSuccessStatusCode();
}
Yukarıdaki kodda yöntemi DeleteItemAsync çağrısında DeleteAsync dır. HTTP DELETE istekleri genellikle gövde içermeyer, yöntemi bir örneğini kabul eden DeleteAsync bir aşırı yükleme HttpContent sağlamaz.
ile farklı HTTP fiilleri kullanma hakkında daha fazla bilgi edinmek HttpClient için bkz. HttpClient .
Giden istek ara yazılımı
HttpClient , giden HTTP istekleri için birbirine bağlanacak işleyiciler için delegelik kavramına sahip. IHttpClientFactory:
Adlandırılmış her istemciye uygulanacak işleyicileri tanımlamayı basitler.
Giden istek ara yazılım işlem hattı oluşturmak için birden çok işleyicinin kaydını ve zincirlesini destekler. Bu işleyicilerin her biri, giden istekten önce ve sonra iş gerçekleştire bir işleyicidir. Bu düzen:
- , ağ trafiğinde gelen ara yazılım işlem hattına ASP.NET Core.
- HTTP istekleriyle ilgili çapraz kesme endişelerini yönetmek için bir mekanizma sağlar, örneğin:
- Önbelleğe alma
- hata işleme
- Seri -leştirme
- günlüğe kaydetme
Bir işleyiciyi tapan oluşturmak için:
- 'den DelegatingHandler türetin.
- geçersiz SendAsync kılın. İsteği işlem hattındaki sonraki işleyiciye geçirmeden önce kodu yürütün:
public class ValidateHeaderHandler : DelegatingHandler
{
protected override async Task<HttpResponseMessage> SendAsync(
HttpRequestMessage request,
CancellationToken cancellationToken)
{
if (!request.Headers.Contains("X-API-KEY"))
{
return new HttpResponseMessage(HttpStatusCode.BadRequest)
{
Content = new StringContent(
"You must supply an API key header called X-API-KEY")
};
}
return await base.SendAsync(request, cancellationToken);
}
}
Yukarıdaki kod, üst X-API-KEY bilginin istekte olup olduğunu denetler. Eksikse X-API-KEY BadRequest döndürülür.
ile yapılandırmasına birden fazla işleyici HttpClient Microsoft.Extensions.DependencyInjection.HttpClientBuilderExtensions.AddHttpMessageHandler eklenebilir:
public void ConfigureServices(IServiceCollection services)
{
services.AddTransient<ValidateHeaderHandler>();
services.AddHttpClient("externalservice", c =>
{
// Assume this is an "external" service which requires an API KEY
c.BaseAddress = new Uri("https://localhost:5001/");
})
.AddHttpMessageHandler<ValidateHeaderHandler>();
// Remaining code deleted for brevity.
Yukarıdaki kodda , ValidateHeaderHandler DI ile kaydedilmiştir. Kaydedildiktan AddHttpMessageHandler sonra, işleyicinin türünü geçerek çağrıl olabilir.
Birden çok işleyici, yürütmeleri gereken sırayla kayded olabilir. Son işleyici isteği yürütene kadar her işleyici HttpClientHandler sonraki işleyiciyi sarmalar:
services.AddTransient<SecureRequestHandler>();
services.AddTransient<RequestDataHandler>();
services.AddHttpClient("clientwithhandlers")
// This handler is on the outside and called first during the
// request, last during the response.
.AddHttpMessageHandler<SecureRequestHandler>()
// This handler is on the inside, closest to the request being
// sent.
.AddHttpMessageHandler<RequestDataHandler>();
Giden istek ara yazılımında DI kullanma
Yeni IHttpClientFactory bir delegating işleyicisi oluşturduğunda, işleyicinin oluşturucu parametrelerini yerine getirmek için DI kullanır. IHttpClientFactory her işleyici için ayrı bir DI kapsamı oluşturur ve bu da işleyici kapsamlı bir hizmet tükettiği zaman şaşırtıcı davranışlara yol açabilirsiniz.
Örneğin, tanımlayıcıya sahip bir işlem olarak bir görevi temsil eden aşağıdaki arabirimini ve uygulamasını göz önünde OperationId bulundurabilirsiniz:
public interface IOperationScoped
{
string OperationId { get; }
}
public class OperationScoped : IOperationScoped
{
public string OperationId { get; } = Guid.NewGuid().ToString()[^4..];
}
Adı da anlaşılacağı IOperationScoped gibi, kapsamlı bir yaşam süresi kullanılarak DI'ye kaydedilir:
public void ConfigureServices(IServiceCollection services)
{
services.AddDbContext<TodoContext>(options =>
options.UseInMemoryDatabase("TodoItems"));
services.AddHttpContextAccessor();
services.AddHttpClient<TodoClient>((sp, httpClient) =>
{
var httpRequest = sp.GetRequiredService<IHttpContextAccessor>().HttpContext.Request;
// For sample purposes, assume TodoClient is used in the context of an incoming request.
httpClient.BaseAddress = new Uri(UriHelper.BuildAbsolute(httpRequest.Scheme,
httpRequest.Host, httpRequest.PathBase));
httpClient.Timeout = TimeSpan.FromSeconds(5);
});
services.AddScoped<IOperationScoped, OperationScoped>();
services.AddTransient<OperationHandler>();
services.AddTransient<OperationResponseHandler>();
services.AddHttpClient("Operation")
.AddHttpMessageHandler<OperationHandler>()
.AddHttpMessageHandler<OperationResponseHandler>()
.SetHandlerLifetime(TimeSpan.FromSeconds(5));
services.AddControllers();
services.AddRazorPages();
}
Aşağıdaki delegating işleyicisi, giden isteğin IOperationScoped üst bilgisini X-OPERATION-ID ayarlamak için kullanır:
public class OperationHandler : DelegatingHandler
{
private readonly IOperationScoped _operationService;
public OperationHandler(IOperationScoped operationScoped)
{
_operationService = operationScoped;
}
protected async override Task<HttpResponseMessage> SendAsync(
HttpRequestMessage request, CancellationToken cancellationToken)
{
request.Headers.Add("X-OPERATION-ID", _operationService.OperationId);
return await base.SendAsync(request, cancellationToken);
}
}
İndirme [ HttpRequestsSample ] sayfasında](https://github.com/dotnet/AspNetCore.Docs/tree/main/aspnetcore/fundamentals/http-requests/samples/3.x/HttpRequestsSample)sayfasına gidin /Operation ve sayfayı yenileyin. İstek kapsamı değeri her istek için değişir, ancak işleyici kapsamı değeri yalnızca 5 saniyede bir değişir.
İşleyiciler herhangi bir kapsamda hizmetlere bağımlı olabilir. İşleyicinin bağımlı olduğu hizmetler, işleyici atılması sırasında atılması.
İstek başına durumu ileti işleyicileriyle paylaşmak için aşağıdaki yaklaşımlardan birini kullanın:
- HttpRequestMessage.Properties kullanarak verileri işleyiciye iletin.
- Geçerli IHttpContextAccessor i isteğine erişmek için kullanın.
- Verileri geçmek AsyncLocal<T> için özel bir depolama nesnesi oluşturun.
Polly tabanlı işleyicileri kullanma
IHttpClientFactory, Polly üçüncü taraf kitaplığıyla tümleştirildi. Polly, .NET için kapsamlı bir resilians ve geçici hata işleme kitaplığıdır. Geliştiricilerin Retry, Circuit Breaker, Timeout, Bulkhead Isolation ve Fallback gibi ilkeleri akıcı ve iş parçacığı güvenli bir şekilde ifade etmelerini sağlar.
Uzantı yöntemleri, yapılandırılmış örneklerle Polly ilkelerinin kullanımını etkinleştirmek için HttpClient sağlanır. Polly uzantıları, istemcilere Polly tabanlı işleyiciler eklemeyi destekler. Polly, Microsoft.Extensions.Http.Polly NuGet gerektirir.
Geçici hataları işleme
Hatalar genellikle dış HTTP çağrıları geçici olduğunda oluşur. AddTransientHttpErrorPolicy , geçici hataları işlemek için bir ilkenin tanımlanmalıdır. ile yapılandırılan AddTransientHttpErrorPolicy ilkeler aşağıdaki yanıtları işlemektedir:
- HttpRequestException
- HTTP 5xx
- HTTP 408
AddTransientHttpErrorPolicy , olası bir PolicyBuilder geçici hatayı temsil eden hataları işlemek için yapılandırılmış bir nesneye erişim sağlar:
public void ConfigureServices(IServiceCollection services)
{
services.AddHttpClient<UnreliableEndpointCallerService>()
.AddTransientHttpErrorPolicy(p =>
p.WaitAndRetryAsync(3, _ => TimeSpan.FromMilliseconds(600)));
// Remaining code deleted for brevity.
Yukarıdaki kodda bir WaitAndRetryAsync ilke tanımlanmıştır. Başarısız istekler denemeler arasında 600 ms gecikmeyle üç kez yeniden denendi.
İlkeleri dinamik olarak seçme
Uzantı yöntemleri, Polly tabanlı işleyiciler eklemek için sağlanır, örneğin, AddPolicyHandler . Aşağıdaki aşırı AddPolicyHandler yükleme, hangi ilkenin uygulanacak olduğuna karar verme isteğini inceler:
var timeout = Policy.TimeoutAsync<HttpResponseMessage>(
TimeSpan.FromSeconds(10));
var longTimeout = Policy.TimeoutAsync<HttpResponseMessage>(
TimeSpan.FromSeconds(30));
services.AddHttpClient("conditionalpolicy")
// Run some code to select a policy based on the request
.AddPolicyHandler(request =>
request.Method == HttpMethod.Get ? timeout : longTimeout);
Yukarıdaki kodda, giden istek bir HTTP GET ise 10 saniyelik bir zaman aşımı uygulanır. Diğer tüm HTTP yöntemleri için 30 saniyelik bir zaman aşımı kullanılır.
Birden çok Polly işleyicisi ekleme
Polly ilkelerini iç içe yerleştirme yaygındır:
services.AddHttpClient("multiplepolicies")
.AddTransientHttpErrorPolicy(p => p.RetryAsync(3))
.AddTransientHttpErrorPolicy(
p => p.CircuitBreakerAsync(5, TimeSpan.FromSeconds(30)));
Yukarıdaki örnekte:
- İki işleyici eklenir.
- İlk işleyici bir AddTransientHttpErrorPolicy yeniden deneme ilkesi eklemek için kullanır. Başarısız istekler en fazla üç kez yeniden denendi.
- İkinci çağrı
AddTransientHttpErrorPolicybir devre kesici ilkesi ekler. 5 başarısız deneme sırayla gerçekleşirse 30 saniye daha dış istek engellenir. Devre kesici ilkeleri durum bilgilidir. Bu istemci aracılığıyla yapılan tüm çağrılar aynı bağlantı hattı durumunu paylaşır.
Polly kayıt defterinden ilke ekleme
Düzenli olarak kullanılan ilkeleri yönetmeye yönelik bir yaklaşım, bunları bir kez tanımlamak ve bir ile PolicyRegistry kaydetmektir.
Aşağıdaki kodda:
- "Normal" ve "uzun" ilkeler eklenir.
- AddPolicyHandlerFromRegistry kayıt defterinden "normal" ve "uzun" ilkeleri ekler.
public void ConfigureServices(IServiceCollection services)
{
var timeout = Policy.TimeoutAsync<HttpResponseMessage>(
TimeSpan.FromSeconds(10));
var longTimeout = Policy.TimeoutAsync<HttpResponseMessage>(
TimeSpan.FromSeconds(30));
var registry = services.AddPolicyRegistry();
registry.Add("regular", timeout);
registry.Add("long", longTimeout);
services.AddHttpClient("regularTimeoutHandler")
.AddPolicyHandlerFromRegistry("regular");
services.AddHttpClient("longTimeoutHandler")
.AddPolicyHandlerFromRegistry("long");
// Remaining code deleted for brevity.
ve IHttpClientFactory Polly tümleştirmeleri hakkında daha fazla bilgi için bkz. Polly wiki.
HttpClient ve yaşam süresi yönetimi
üzerinde HttpClient her çağrıldında yeni CreateClient bir örnek IHttpClientFactory döndürülür. Adlandırılmış HttpMessageHandler istemci başına oluşturulur. Fabrika örneklerin yaşam HttpMessageHandler sürelerini yönetir.
IHttpClientFactory , HttpMessageHandler kaynak tüketimini azaltmak için fabrika tarafından oluşturulan örnekleri havuza alar. Yaşam HttpMessageHandler süresi dolmamışsa yeni bir örnek oluşturulurken HttpClient örnek havuzdan yeniden kullanılabilir.
Her işleyici genellikle kendi temel HTTP bağlantılarını yönetirken işleyicilerin havuzu tercih edilir. Gerekenden daha fazla işleyici oluşturmak bağlantı gecikmeleri ile sonuçlandırabilirsiniz. Bazı işleyiciler ayrıca bağlantıları süresiz olarak açık tutmakta ve bu da işleyicinin DNS (Etki Alanı Adı Sistemi) değişikliklerine tepki vermesini önlemektedir.
Varsayılan işleyicinin ömrü iki dakikadır. Varsayılan değer, adlandırılmış istemci başına geçersiz kılınabilir:
public void ConfigureServices(IServiceCollection services)
{
services.AddHttpClient("extendedhandlerlifetime")
.SetHandlerLifetime(TimeSpan.FromMinutes(5));
// Remaining code deleted for brevity.
HttpClient örnekler genellikle atılması gerekmeden .NET nesneleri olarak kabul edilebilir. Atma, giden istekleri iptal eder ve HttpClient çağrıldikten sonra verilen örneğin kullanılamaz durumda olacağını garanti Dispose eder. IHttpClientFactory örnekler tarafından kullanılan kaynakları izler ve HttpClient atlar.
Tek bir örneği HttpClient uzun süre canlı tutmak, kullanılmaya başlamadan önce yaygın olarak kullanılan bir desendir. IHttpClientFactory bu düzen, 'a katıldıktan sonra gereksiz hale IHttpClientFactory gelir.
IHttpClientFactory'nin alternatifleri
IHttpClientFactoryDI özellikli bir uygulamada kullanmak şunları önler:
- Örnekleri havuza alan kaynak tükenme
HttpMessageHandlersorunları. - Düzenli aralıklarla örneklerin atarak eski DNS
HttpMessageHandlersorunları.
Uzun süreli bir örneği kullanarak önceki sorunları çözmenin alternatif yolları SocketsHttpHandler vardır.
- Uygulama başlatıldığında
SocketsHttpHandlerbir örneği oluşturun ve uygulamanın ömrü boyunca bunu kullanın. - DNS PooledConnectionLifetime yenileme zamanlarına göre uygun bir değere yapılandırma.
- Gerektiğinde
HttpClientkullanaraknew HttpClient(handler, disposeHandler: false)örnekler oluşturun.
Yukarıdaki yaklaşımlar, kaynak yönetimi sorunlarını da IHttpClientFactory benzer şekilde çözer.
- örnekler
SocketsHttpHandlerarasında bağlantı paylaşımıHttpClientsağlar. Bu paylaşım yuva tükenmesini önler. - Eski
SocketsHttpHandlerDNS sorunlarını önlemek için bağlantıları uygun şekildePooledConnectionLifetimedöngüye alar.
CookieS
Havuza alan HttpMessageHandler örnekler, nesnelerin CookieContainer paylaşılır olmasıyla sonuç verir. Beklentisiz nesne paylaşımı CookieContainer genellikle yanlış koda neden olur. gerektiren uygulamalar için cookie şu iki işlemden birini değerlendirin:
- Otomatik işlemeyi devre cookie dışı bırakma
- Kaçın -arak
IHttpClientFactory
Otomatik ConfigurePrimaryHttpMessageHandler işlemeyi devre dışı bırakmak için cookie çağrısı:
services.AddHttpClient("configured-disable-automatic-cookies")
.ConfigurePrimaryHttpMessageHandler(() =>
{
return new HttpClientHandler()
{
UseCookies = false,
};
});
Günlüğe Kaydetme
Tüm istekler IHttpClientFactory için kayıt günlüğü iletileriyle oluşturulan istemciler. Varsayılan günlük iletilerini görmek için günlük yapılandırmasında uygun bilgi düzeyini etkinleştirin. İstek üst bilgilerini günlüğe kaydetme gibi ek günlükler yalnızca izleme düzeyinde dahil edilir.
Her istemci için kullanılan günlük kategorisi istemcinin adını içerir. Örneğin MyNamedClient adlı bir istemci iletileri "System.Net.Http.HttpClient" kategorisiyle günlüğe kaydeder. MyNamedClient. LogicalHandler". LogicalHandler ile son ekli iletiler, istek işleyicisi işlem hattının dışında oluşur. İstekte iletiler, işlem hattında diğer işleyiciler tarafından işlenmeden önce günlüğe kaydedilir. Yanıtta, diğer işlem hattı işleyicileri yanıtı aldıktan sonra iletiler günlüğe kaydedilir.
Günlük, istek işleyicisi işlem hattında da gerçekleşir. MyNamedClient örneğinde, bu iletiler "System.Net.Http.HttpClient" günlük kategorisiyle günlüğe kaydedilir. MyNamedClient. ClientHandler". İstek için, bu durum diğer tüm işleyiciler çalıştırktan ve istek gönderilmeden hemen önce gerçekleşir. Yanıtta bu günlük, işleyici işlem hattına geri dönmeden önce yanıtın durumunu içerir.
İşlem hattının dışında ve içinde günlüğe kaydetmeyi etkinleştirmek, diğer işlem hattı işleyicileri tarafından yapılan değişikliklerin incesini sağlar. Bu, istek üst bilgisinde veya yanıt durum kodunda yapılan değişiklikleri içerebilir.
İstemcinin adını günlük kategorisine dahil olmak, belirli adlandırılmış istemciler için günlük filtrelemeyi sağlar.
HttpMessageHandler'ı yapılandırma
İstemci tarafından kullanılan iç yapılandırmayı HttpMessageHandler denetlemeniz gerekebilir.
Adlandırılmış IHttpClientBuilder veya türe bağlı istemciler ekliyken bir döndürülür. Uzantı ConfigurePrimaryHttpMessageHandler yöntemi bir temsilci tanımlamak için kullanılabilir. Temsilci, bu istemci tarafından kullanılan birincili HttpMessageHandler oluşturmak ve yapılandırmak için kullanılır:
public void ConfigureServices(IServiceCollection services)
{
services.AddHttpClient("configured-inner-handler")
.ConfigurePrimaryHttpMessageHandler(() =>
{
return new HttpClientHandler()
{
AllowAutoRedirect = false,
UseDefaultCredentials = true
};
});
// Remaining code deleted for brevity.
Konsol uygulamasında IHttpClientFactory kullanma
Bir konsol uygulamasında, aşağıdaki paket başvurularını projeye ekleyin:
Aşağıdaki örnekte:
- IHttpClientFactory , Genel Ana Bilgisayar'ın hizmet kapsayıcısı içinde kayıtlıdır.
MyService, hizmetten bir oluşturmak için kullanılan bir istemci fabrika örneğiHttpClientoluşturur.HttpClientbir web sayfasını almak için kullanılır.Mainhizmetin yöntemini yürütmek ve web sayfası içeriğinin ilkGetPage500 karakteri konsola yazmak için bir kapsam oluşturur.
using System;
using System.Net.Http;
using System.Threading.Tasks;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging;
class Program
{
static async Task<int> Main(string[] args)
{
var builder = new HostBuilder()
.ConfigureServices((hostContext, services) =>
{
services.AddHttpClient();
services.AddTransient<IMyService, MyService>();
}).UseConsoleLifetime();
var host = builder.Build();
try
{
var myService = host.Services.GetRequiredService<IMyService>();
var pageContent = await myService.GetPage();
Console.WriteLine(pageContent.Substring(0, 500));
}
catch (Exception ex)
{
var logger = host.Services.GetRequiredService<ILogger<Program>>();
logger.LogError(ex, "An error occurred.");
}
return 0;
}
public interface IMyService
{
Task<string> GetPage();
}
public class MyService : IMyService
{
private readonly IHttpClientFactory _clientFactory;
public MyService(IHttpClientFactory clientFactory)
{
_clientFactory = clientFactory;
}
public async Task<string> GetPage()
{
// Content from BBC One: Dr. Who website (©BBC)
var request = new HttpRequestMessage(HttpMethod.Get,
"https://www.bbc.co.uk/programmes/b006q2x0");
var client = _clientFactory.CreateClient();
var response = await client.SendAsync(request);
if (response.IsSuccessStatusCode)
{
return await response.Content.ReadAsStringAsync();
}
else
{
return $"StatusCode: {response.StatusCode}";
}
}
}
}
Üst bilgi yayma ara yazılımı
Üst bilgi yayma, ASP.NET Core gelen istekten giden HTTP İstemci isteklerine HTTP üst bilgilerini yayma aracıdır. Üst bilgi yayma kullanmak için:
ara yazılımı ve 'de
HttpClientStartupyapılandırma:public void ConfigureServices(IServiceCollection services) { services.AddControllers(); services.AddHttpClient("MyForwardingClient").AddHeaderPropagation(); services.AddHeaderPropagation(options => { options.Headers.Add("X-TraceId"); }); } public void Configure(IApplicationBuilder app, IWebHostEnvironment env) { if (env.IsDevelopment()) { app.UseDeveloperExceptionPage(); } app.UseHttpsRedirection(); app.UseHeaderPropagation(); app.UseRouting(); app.UseAuthorization(); app.UseEndpoints(endpoints => { endpoints.MapControllers(); }); }İstemci, giden isteklerde yapılandırılmış üst bilgileri içerir:
var client = clientFactory.CreateClient("MyForwardingClient"); var response = client.GetAsync(...);
Ek kaynaklar
Göre: Gordon Larkin, Steve Gordon, Gordonn Condronve Ryan Nowak.
, IHttpClientFactory bir uygulamada örnekleri yapılandırmak ve oluşturmak için HttpClient kaydedile ve kullanılabilir. IHttpClientFactory aşağıdaki avantajları sunar:
- Mantıksal örnekleri adlandırmak ve yapılandırmak için merkezi bir
HttpClientkonum sağlar. Örneğin, github adlı bir istemci kaydedilene ve GitHub. Genel erişim için varsayılan bir istemci kayded olabilir. - içinde işleyiciler için delete aracılığıyla giden ara yazılım kavramını
HttpClientkodlar. içinde işleyicileri seçme avantajını elde etmek için Polly tabanlı ara yazılım için uzantılarHttpClientsağlar. - Temel alınan örneklerin havuzlarını ve yaşam
HttpClientMessageHandlersürelerini yönetir. Otomatik yönetim, yaşam sürelerini el ile yönetme sırasında oluşan yaygın DNS (Etki Alanı Adı Sistemi)HttpClientsorunlarını önler. - Fabrika tarafından oluşturulan istemciler aracılığıyla gönderilen tüm
ILoggeristekler için yapılandırılabilir bir günlük deneyimi (aracılığıyla) ekler.
Örnek kodu görüntüleme veya indirme (indirme).
Bu konu sürümündeki örnek kod, System.Text.Json HTTP yanıtlarında döndürülen JSON içeriğininserializesini almak için kullanır. ve kullanan örnekler Json.NET için ReadAsAsync<T> sürüm seçiciyi kullanarak bu konunun 2.x sürümünü seçin.
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
IHttpClientFactory çağrısıyla kaydedil AddHttpClient olabilir:
public class Startup
{
public Startup(IConfiguration configuration)
{
Configuration = configuration;
}
public IConfiguration Configuration { get; }
public void ConfigureServices(IServiceCollection services)
{
services.AddHttpClient();
// Remaining code deleted for brevity.
IHttpClientFactory, bağımlılık ekleme (DI) kullanılarak talep edilebilir. Aşağıdaki kod bir IHttpClientFactory örnek oluşturmak için HttpClient kullanır:
public class BasicUsageModel : PageModel
{
private readonly IHttpClientFactory _clientFactory;
public IEnumerable<GitHubBranch> Branches { get; private set; }
public bool GetBranchesError { get; private set; }
public BasicUsageModel(IHttpClientFactory clientFactory)
{
_clientFactory = clientFactory;
}
public async Task OnGet()
{
var request = new HttpRequestMessage(HttpMethod.Get,
"https://api.github.com/repos/dotnet/AspNetCore.Docs/branches");
request.Headers.Add("Accept", "application/vnd.github.v3+json");
request.Headers.Add("User-Agent", "HttpClientFactory-Sample");
var client = _clientFactory.CreateClient();
var response = await client.SendAsync(request);
if (response.IsSuccessStatusCode)
{
using var responseStream = await response.Content.ReadAsStreamAsync();
Branches = await JsonSerializer.DeserializeAsync
<IEnumerable<GitHubBranch>>(responseStream);
}
else
{
GetBranchesError = true;
Branches = Array.Empty<GitHubBranch>();
}
}
}
Yukarıdaki IHttpClientFactory örnekte olduğu gibi kullanmak, mevcut bir uygulamayı yeniden düzenlemenin iyi bir yolu olabilir. Bu, nasıl kullanılır? ü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ı
HttpClientgerekir. - Çoğunda
HttpClientfarklı yapılandırmalar vardır.
adlı bir için HttpClient yapılandırma, içinde kayıt sırasında belirtilebilir: Startup.ConfigureServices
services.AddHttpClient("github", c =>
{
c.BaseAddress = new Uri("https://api.github.com/");
// Github API versioning
c.DefaultRequestHeaders.Add("Accept", "application/vnd.github.v3+json");
// Github requires a user-agent
c.DefaultRequestHeaders.Add("User-Agent", "HttpClientFactory-Sample");
});
Önceki kodda istemci aşağıdakilerle yapılandırılmıştır:
- Temel
https://api.github.com/adres. - GitHub API'si ile çalışmak için GitHub gerekir.
CreateClient
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:
public class NamedClientModel : PageModel
{
private readonly IHttpClientFactory _clientFactory;
public IEnumerable<GitHubPullRequest> PullRequests { get; private set; }
public bool GetPullRequestsError { get; private set; }
public bool HasPullRequests => PullRequests.Any();
public NamedClientModel(IHttpClientFactory clientFactory)
{
_clientFactory = clientFactory;
}
public async Task OnGet()
{
var request = new HttpRequestMessage(HttpMethod.Get,
"repos/dotnet/AspNetCore.Docs/pulls");
var client = _clientFactory.CreateClient("github");
var response = await client.SendAsync(request);
if (response.IsSuccessStatusCode)
{
using var responseStream = await response.Content.ReadAsStreamAsync();
PullRequests = await JsonSerializer.DeserializeAsync
<IEnumerable<GitHubPullRequest>>(responseStream);
}
else
{
GetPullRequestsError = true;
PullRequests = Array.Empty<GitHubPullRequest>();
}
}
}
Yukarıdaki kodda isteğin bir konak adı belirtmesi gerekm yok. İstemci için yapılandırılan temel adres kullanıldığından 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ğlar.
- Yapılandırmak ve belirli bir ile etkileşim kurmak için tek bir konum
HttpClientsağ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:
public class GitHubService
{
public HttpClient Client { get; }
public GitHubService(HttpClient client)
{
client.BaseAddress = new Uri("https://api.github.com/");
// GitHub API versioning
client.DefaultRequestHeaders.Add("Accept",
"application/vnd.github.v3+json");
// GitHub requires a user-agent
client.DefaultRequestHeaders.Add("User-Agent",
"HttpClientFactory-Sample");
Client = client;
}
public async Task<IEnumerable<GitHubIssue>> GetAspNetDocsIssues()
{
return await Client.GetFromJsonAsync<IEnumerable<GitHubIssue>>(
"/repos/aspnet/AspNetCore.Docs/issues?state=open&sort=created&direction=desc");
}
}
Yukarıdaki kodda:
- Yapılandırma türüne göre istemciye taşınır.
- nesnesi
HttpClientgenel bir özellik olarak ortaya çıkar.
İşlevselliği ortaya çıkaran API'ye özgü HttpClient yöntemler oluşturulabilir. Örneğin yöntemi, GetAspNetDocsIssues açık sorunları almak için kodu kapsüller.
Aşağıdaki kod, türü AddHttpClient türü doğru olan bir istemci Startup.ConfigureServices sınıfını kaydetmek için çağrısında dır:
services.AddHttpClient<GitHubService>();
Türe sahip istemci, DI ile geçici olarak kaydedilir. Yukarıdaki kodda, AddHttpClient geçici bir hizmet olarak GitHubService kaydolr. Bu kayıt, aşağıdaki işlemleri yapmak için bir fabrika yöntemi kullanır:
HttpClientörneği oluşturun.- örneğini oluşturucuya
GitHubServicegeçirmesi için birHttpClientörneği oluşturun.
Türü yazilen istemci doğrudan ekleme ve tüketilebilir:
public class TypedClientModel : PageModel
{
private readonly GitHubService _gitHubService;
public IEnumerable<GitHubIssue> LatestIssues { get; private set; }
public bool HasIssue => LatestIssues.Any();
public bool GetIssuesError { get; private set; }
public TypedClientModel(GitHubService gitHubService)
{
_gitHubService = gitHubService;
}
public async Task OnGet()
{
try
{
LatestIssues = await _gitHubService.GetAspNetDocsIssues();
}
catch(HttpRequestException)
{
GetIssuesError = true;
LatestIssues = Array.Empty<GitHubIssue>();
}
}
}
Türü belirtilmiş bir istemcinin yapılandırması, türü belirtilmiş istemcinin oluşturucusu yerine 'de Startup.ConfigureServices kayıt sırasında belirtilebilir:
services.AddHttpClient<RepoService>(c =>
{
c.BaseAddress = new Uri("https://api.github.com/");
c.DefaultRequestHeaders.Add("Accept", "application/vnd.github.v3+json");
c.DefaultRequestHeaders.Add("User-Agent", "HttpClientFactory-Sample");
});
HttpClienttürüne göre bir istemci içinde kapsül olabilir. Bunu bir özellik olarak açığa çıkararak değil, örneği dahili olarak çağıran HttpClient bir yöntem tanımlayın:
public class RepoService
{
// _httpClient isn't exposed publicly
private readonly HttpClient _httpClient;
public RepoService(HttpClient client)
{
_httpClient = client;
}
public async Task<IEnumerable<string>> GetRepos()
{
var response = await _httpClient.GetAsync("aspnet/repos");
response.EnsureSuccessStatusCode();
using var responseStream = await response.Content.ReadAsStreamAsync();
return await JsonSerializer.DeserializeAsync
<IEnumerable<string>>(responseStream);
}
}
Yukarıdaki kodda, HttpClient özel bir alanda depolanır. erişimi HttpClient ortak yöntemine GetRepos göredir.
Oluşturulan istemciler
IHttpClientFactoryYeniden Sığdır gibi üçüncü taraf kitaplıklarla birlikte kullanılabilir. Yeniden sığdır, .NET için bir REST kitaplığıdır. REST API'leri canlı arabirimlere dönüştürür. arabiriminin bir uygulaması, dış HTTP çağrıları yapmak RestService için kullanılarak dinamik olarak HttpClient oluşturulur.
Dış API'yi ve yanıtını temsil etmek için bir arabirim ve yanıt tanımlanır:
public interface IHelloClient
{
[Get("/helloworld")]
Task<Reply> GetMessageAsync();
}
public class Reply
{
public string Message { get; set; }
}
Türü oluşturulan bir istemci, uygulama oluşturmak için Yeniden Sığdır kullanılarak eklenebilir:
public void ConfigureServices(IServiceCollection services)
{
services.AddHttpClient("hello", c =>
{
c.BaseAddress = new Uri("http://localhost:5000");
})
.AddTypedClient(c => Refit.RestService.For<IHelloClient>(c));
services.AddControllers();
}
Tanımlanan arabirim gerektiğinde DI ve Yeniden Sığdır tarafından sağlanan uygulamayla birlikte kullanılabilir:
[ApiController]
public class ValuesController : ControllerBase
{
private readonly IHelloClient _client;
public ValuesController(IHelloClient client)
{
_client = client;
}
[HttpGet("/")]
public async Task<ActionResult<Reply>> Index()
{
return await _client.GetMessageAsync();
}
}
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 örnekte, bir HTTP POST isteğinin nasıl gerçekleştirl olduğu gösterir:
public async Task CreateItemAsync(TodoItem todoItem)
{
var todoItemJson = new StringContent(
JsonSerializer.Serialize(todoItem, _jsonSerializerOptions),
Encoding.UTF8,
"application/json");
using var httpResponse =
await _httpClient.PostAsync("/api/TodoItems", todoItemJson);
httpResponse.EnsureSuccessStatusCode();
}
Yukarıdaki kodda CreateItemAsync yöntemi:
- kullanarak parametresini
TodoItemJSON olarak seri haleSystem.Text.Jsongetirme. Bu, serileştirme JsonSerializerOptions işlemini yapılandırmak için bir örneğini kullanır. - HTTP isteğinin StringContent gövdesinde göndermek için serileştirilmiş JSON'u paketleye bir örneği oluşturur.
- PostAsyncBelirtilen URL'ye JSON içeriğini göndermek için çağrıları. Bu, HttpClient.BaseAddress'e eklenen göreli bir URL'dir.
- Yanıt EnsureSuccessStatusCode durumu kodu başarılı olduğunu belirtenin dışında bir özel durum oluşturur.
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österir:
public async Task SaveItemAsync(TodoItem todoItem)
{
var todoItemJson = new StringContent(
JsonSerializer.Serialize(todoItem),
Encoding.UTF8,
"application/json");
using var httpResponse =
await _httpClient.PutAsync($"/api/TodoItems/{todoItem.Id}", todoItemJson);
httpResponse.EnsureSuccessStatusCode();
}
Yukarıdaki kod, POST örneğine çok benzer. yöntemi SaveItemAsync yerine PutAsync yöntemini PostAsync çağıran.
Aşağıdaki örnekte bir HTTP DELETE isteği gösterir:
public async Task DeleteItemAsync(long itemId)
{
using var httpResponse =
await _httpClient.DeleteAsync($"/api/TodoItems/{itemId}");
httpResponse.EnsureSuccessStatusCode();
}
Yukarıdaki kodda yöntemi DeleteItemAsync çağrısında DeleteAsync dır. HTTP DELETE istekleri genellikle gövde içermeyer, yöntemi bir örneğini kabul eden DeleteAsync bir aşırı yükleme HttpContent sağlamaz.
ile farklı HTTP fiilleri kullanma hakkında daha fazla bilgi edinmek HttpClient için bkz. HttpClient .
Giden istek ara yazılımı
HttpClient , giden HTTP istekleri için birbirine bağlanacak işleyiciler için delegelik kavramına sahip. IHttpClientFactory:
Adlandırılmış her istemciye uygulanacak işleyicileri tanımlamayı basitler.
Giden istek ara yazılım işlem hattı oluşturmak için birden çok işleyicinin kaydını ve zincirlesini destekler. Bu işleyicilerin her biri, giden istekten önce ve sonra iş gerçekleştire bir işleyicidir. Bu düzen:
- , ağ trafiğinde gelen ara yazılım işlem hattına ASP.NET Core.
- HTTP istekleriyle ilgili çapraz kesme endişelerini yönetmek için bir mekanizma sağlar, örneğin:
- Önbelleğe alma
- hata işleme
- Seri -leştirme
- günlüğe kaydetme
Bir işleyiciyi tapan oluşturmak için:
- 'den DelegatingHandler türetin.
- geçersiz SendAsync kılın. İsteği işlem hattındaki sonraki işleyiciye geçirmeden önce kodu yürütün:
public class ValidateHeaderHandler : DelegatingHandler
{
protected override async Task<HttpResponseMessage> SendAsync(
HttpRequestMessage request,
CancellationToken cancellationToken)
{
if (!request.Headers.Contains("X-API-KEY"))
{
return new HttpResponseMessage(HttpStatusCode.BadRequest)
{
Content = new StringContent(
"You must supply an API key header called X-API-KEY")
};
}
return await base.SendAsync(request, cancellationToken);
}
}
Yukarıdaki kod, üst X-API-KEY bilginin istekte olup olduğunu denetler. Eksikse X-API-KEY BadRequest döndürülür.
ile yapılandırmasına birden fazla işleyici HttpClient Microsoft.Extensions.DependencyInjection.HttpClientBuilderExtensions.AddHttpMessageHandler eklenebilir:
public void ConfigureServices(IServiceCollection services)
{
services.AddTransient<ValidateHeaderHandler>();
services.AddHttpClient("externalservice", c =>
{
// Assume this is an "external" service which requires an API KEY
c.BaseAddress = new Uri("https://localhost:5001/");
})
.AddHttpMessageHandler<ValidateHeaderHandler>();
// Remaining code deleted for brevity.
Yukarıdaki kodda , ValidateHeaderHandler DI ile kaydedilmiştir. Kaydedildiktan AddHttpMessageHandler sonra, işleyicinin türünü geçerek çağrıl olabilir.
Birden çok işleyici, yürütmeleri gereken sırayla kayded olabilir. Son işleyici isteği yürütene kadar her işleyici HttpClientHandler sonraki işleyiciyi sarmalar:
services.AddTransient<SecureRequestHandler>();
services.AddTransient<RequestDataHandler>();
services.AddHttpClient("clientwithhandlers")
// This handler is on the outside and called first during the
// request, last during the response.
.AddHttpMessageHandler<SecureRequestHandler>()
// This handler is on the inside, closest to the request being
// sent.
.AddHttpMessageHandler<RequestDataHandler>();
Giden istek ara yazılımında DI kullanma
Yeni IHttpClientFactory bir delegating işleyicisi oluşturduğunda, işleyicinin oluşturucu parametrelerini yerine getirmek için DI kullanır. IHttpClientFactory her işleyici için ayrı bir DI kapsamı oluşturur ve bu da işleyici kapsamlı bir hizmet tükettiği zaman şaşırtıcı davranışlara yol açabilirsiniz.
Örneğin, tanımlayıcıya sahip bir işlem olarak bir görevi temsil eden aşağıdaki arabirimini ve uygulamasını göz önünde OperationId bulundurabilirsiniz:
public interface IOperationScoped
{
string OperationId { get; }
}
public class OperationScoped : IOperationScoped
{
public string OperationId { get; } = Guid.NewGuid().ToString()[^4..];
}
Adı da anlaşılacağı IOperationScoped gibi, kapsamlı bir yaşam süresi kullanılarak DI'ye kaydedilir:
public void ConfigureServices(IServiceCollection services)
{
services.AddDbContext<TodoContext>(options =>
options.UseInMemoryDatabase("TodoItems"));
services.AddHttpContextAccessor();
services.AddHttpClient<TodoClient>((sp, httpClient) =>
{
var httpRequest = sp.GetRequiredService<IHttpContextAccessor>().HttpContext.Request;
// For sample purposes, assume TodoClient is used in the context of an incoming request.
httpClient.BaseAddress = new Uri(UriHelper.BuildAbsolute(httpRequest.Scheme,
httpRequest.Host, httpRequest.PathBase));
httpClient.Timeout = TimeSpan.FromSeconds(5);
});
services.AddScoped<IOperationScoped, OperationScoped>();
services.AddTransient<OperationHandler>();
services.AddTransient<OperationResponseHandler>();
services.AddHttpClient("Operation")
.AddHttpMessageHandler<OperationHandler>()
.AddHttpMessageHandler<OperationResponseHandler>()
.SetHandlerLifetime(TimeSpan.FromSeconds(5));
services.AddControllers();
services.AddRazorPages();
}
Aşağıdaki delegating işleyicisi, giden isteğin IOperationScoped üst bilgisini X-OPERATION-ID ayarlamak için kullanır:
public class OperationHandler : DelegatingHandler
{
private readonly IOperationScoped _operationService;
public OperationHandler(IOperationScoped operationScoped)
{
_operationService = operationScoped;
}
protected async override Task<HttpResponseMessage> SendAsync(
HttpRequestMessage request, CancellationToken cancellationToken)
{
request.Headers.Add("X-OPERATION-ID", _operationService.OperationId);
return await base.SendAsync(request, cancellationToken);
}
}
İndirme [ HttpRequestsSample ] sayfasında](https://github.com/dotnet/AspNetCore.Docs/tree/main/aspnetcore/fundamentals/http-requests/samples/3.x/HttpRequestsSample)sayfasına gidin /Operation ve sayfayı yenileyin. İstek kapsamı değeri her istek için değişir, ancak işleyici kapsamı değeri yalnızca 5 saniyede bir değişir.
İşleyiciler herhangi bir kapsamda hizmetlere bağımlı olabilir. İşleyicinin bağımlı olduğu hizmetler, işleyici atıldıkları zaman atıldı.
İstek başına durumu ileti işleyicileriyle paylaşmak için aşağıdaki yaklaşımlardan birini kullanın:
- HttpRequestMessage.Properties kullanarak verileri işleyiciye iletin.
- Geçerli IHttpContextAccessor i isteğine erişmek için kullanın.
- Verileri geçmek AsyncLocal<T> için özel bir depolama nesnesi oluşturun.
Polly tabanlı işleyicileri kullanma
IHttpClientFactory, Polly üçüncü taraf kitaplığıyla tümleştirildi. Polly, .NET için kapsamlı bir resilians ve geçici hata işleme kitaplığıdır. Geliştiricilerin Retry, Circuit Breaker, Timeout, Bulkhead Isolation ve Fallback gibi ilkeleri akıcı ve iş parçacığı güvenli bir şekilde ifade etmelerini sağlar.
Uzantı yöntemleri, yapılandırılmış örneklerle Polly ilkelerinin kullanımını etkinleştirmek için HttpClient sağlanır. Polly uzantıları, istemcilere Polly tabanlı işleyiciler eklemeyi destekler. Polly, Microsoft.Extensions.Http.Polly NuGet gerektirir.
Geçici hataları işleme
Hatalar genellikle dış HTTP çağrıları geçici olduğunda oluşur. AddTransientHttpErrorPolicy , geçici hataları işlemek için bir ilkenin tanımlanmalıdır. ile yapılandırılan AddTransientHttpErrorPolicy ilkeler aşağıdaki yanıtları işlemektedir:
- HttpRequestException
- HTTP 5xx
- HTTP 408
AddTransientHttpErrorPolicy , olası bir PolicyBuilder geçici hatayı temsil eden hataları işlemek için yapılandırılmış bir nesneye erişim sağlar:
public void ConfigureServices(IServiceCollection services)
{
services.AddHttpClient<UnreliableEndpointCallerService>()
.AddTransientHttpErrorPolicy(p =>
p.WaitAndRetryAsync(3, _ => TimeSpan.FromMilliseconds(600)));
// Remaining code deleted for brevity.
Yukarıdaki kodda bir WaitAndRetryAsync ilke tanımlanmıştır. Başarısız istekler denemeler arasında 600 ms gecikmeyle üç kez yeniden denendi.
İlkeleri dinamik olarak seçme
Uzantı yöntemleri, Polly tabanlı işleyiciler eklemek için sağlanır, örneğin, AddPolicyHandler . Aşağıdaki aşırı AddPolicyHandler yükleme, hangi ilkenin uygulanacak olduğuna karar verme isteğini inceler:
var timeout = Policy.TimeoutAsync<HttpResponseMessage>(
TimeSpan.FromSeconds(10));
var longTimeout = Policy.TimeoutAsync<HttpResponseMessage>(
TimeSpan.FromSeconds(30));
services.AddHttpClient("conditionalpolicy")
// Run some code to select a policy based on the request
.AddPolicyHandler(request =>
request.Method == HttpMethod.Get ? timeout : longTimeout);
Yukarıdaki kodda, giden istek bir HTTP GET ise 10 saniyelik bir zaman aşımı uygulanır. Diğer tüm HTTP yöntemleri için 30 saniyelik bir zaman aşımı kullanılır.
Birden çok Polly işleyicisi ekleme
Polly ilkelerini iç içe yerleştirme yaygındır:
services.AddHttpClient("multiplepolicies")
.AddTransientHttpErrorPolicy(p => p.RetryAsync(3))
.AddTransientHttpErrorPolicy(
p => p.CircuitBreakerAsync(5, TimeSpan.FromSeconds(30)));
Yukarıdaki örnekte:
- İki işleyici eklenir.
- İlk işleyici bir AddTransientHttpErrorPolicy yeniden deneme ilkesi eklemek için kullanır. Başarısız istekler en fazla üç kez yeniden denendi.
- İkinci çağrı
AddTransientHttpErrorPolicybir devre kesici ilkesi ekler. 5 başarısız deneme sırayla gerçekleşirse 30 saniye daha dış istek engellenir. Devre kesici ilkeleri durum bilgilidir. Bu istemci aracılığıyla yapılan tüm çağrılar aynı bağlantı hattı durumunu paylaşır.
Polly kayıt defterinden ilke ekleme
Düzenli olarak kullanılan ilkeleri yönetmeye yönelik bir yaklaşım, bunları bir kez tanımlamak ve bir ile PolicyRegistry kaydetmektir.
Aşağıdaki kodda:
- "Normal" ve "uzun" ilkeler eklenir.
- AddPolicyHandlerFromRegistry kayıt defterinden "normal" ve "uzun" ilkeleri ekler.
public void ConfigureServices(IServiceCollection services)
{
var timeout = Policy.TimeoutAsync<HttpResponseMessage>(
TimeSpan.FromSeconds(10));
var longTimeout = Policy.TimeoutAsync<HttpResponseMessage>(
TimeSpan.FromSeconds(30));
var registry = services.AddPolicyRegistry();
registry.Add("regular", timeout);
registry.Add("long", longTimeout);
services.AddHttpClient("regularTimeoutHandler")
.AddPolicyHandlerFromRegistry("regular");
services.AddHttpClient("longTimeoutHandler")
.AddPolicyHandlerFromRegistry("long");
// Remaining code deleted for brevity.
ve IHttpClientFactory Polly tümleştirmeleri hakkında daha fazla bilgi için bkz. Polly wiki.
HttpClient ve yaşam süresi yönetimi
üzerinde HttpClient her çağrıldında yeni CreateClient bir örnek IHttpClientFactory döndürülür. Adlandırılmış HttpMessageHandler istemci başına oluşturulur. Fabrika örneklerin yaşam HttpMessageHandler sürelerini yönetir.
IHttpClientFactory , HttpMessageHandler kaynak tüketimini azaltmak için fabrika tarafından oluşturulan örnekleri havuza alar. Yaşam HttpMessageHandler süresi dolmamışsa yeni bir örnek oluşturulurken HttpClient örnek havuzdan yeniden kullanılabilir.
Her işleyici genellikle kendi temel HTTP bağlantılarını yönetirken işleyicilerin havuzu tercih edilir. Gerekenden daha fazla işleyici oluşturmak bağlantı gecikmeleri ile sonuçlandırabilirsiniz. Bazı işleyiciler ayrıca bağlantıları süresiz olarak açık tutmakta ve bu da işleyicinin DNS (Etki Alanı Adı Sistemi) değişikliklerine tepki vermesini önlemektedir.
Varsayılan işleyicinin ömrü iki dakikadır. Varsayılan değer, adlandırılmış istemci başına geçersiz kılınabilir:
public void ConfigureServices(IServiceCollection services)
{
services.AddHttpClient("extendedhandlerlifetime")
.SetHandlerLifetime(TimeSpan.FromMinutes(5));
// Remaining code deleted for brevity.
HttpClient örnekler genellikle atılması gerekmeden .NET nesneleri olarak kabul edilebilir. Atma, giden istekleri iptal eder ve HttpClient çağrıldikten sonra verilen örneğin kullanılamaz durumda olacağını garanti Dispose eder. IHttpClientFactory örnekler tarafından kullanılan kaynakları izler ve HttpClient atlar.
Tek bir örneği HttpClient uzun süre canlı tutmak, kullanılmaya başlamadan önce yaygın olarak kullanılan bir desendir. IHttpClientFactory bu düzen, 'a katıldıktan sonra gereksiz hale IHttpClientFactory gelir.
IHttpClientFactory'nin alternatifleri
IHttpClientFactoryDI özellikli bir uygulamada kullanmak şunları önler:
- Örnekleri havuza alan kaynak tükenme
HttpMessageHandlersorunları. - Düzenli aralıklarla örneklerin atarak eski DNS
HttpMessageHandlersorunları.
Uzun süreli bir örneği kullanarak önceki sorunları çözmenin alternatif yolları SocketsHttpHandler vardır.
- Uygulama başlatıldığında
SocketsHttpHandlerbir örneği oluşturun ve uygulamanın ömrü boyunca bunu kullanın. - DNS PooledConnectionLifetime yenileme zamanlarına göre uygun bir değere yapılandırma.
- Gerektiğinde
HttpClientkullanaraknew HttpClient(handler, disposeHandler: false)örnekler oluşturun.
Yukarıdaki yaklaşımlar, kaynak yönetimi sorunlarını da IHttpClientFactory benzer şekilde çözer.
- örnekler
SocketsHttpHandlerarasında bağlantılarıHttpClientpaylaşıyor. Bu paylaşım yuva tükenmesini önler. - Eski
SocketsHttpHandlerDNS sorunlarını önlemek için bağlantıları uygun şekildePooledConnectionLifetimedöngüye alar.
CookieS
Havuza alan HttpMessageHandler örnekler, nesnelerin CookieContainer paylaşılır olmasıyla sonuç verir. Beklentisiz nesne paylaşımı CookieContainer genellikle yanlış koda neden olur. gerektiren uygulamalar için cookie şu iki işlemden birini değerlendirin:
- Otomatik işlemeyi devre cookie dışı bırakma
- Kaçın -arak
IHttpClientFactory
Otomatik ConfigurePrimaryHttpMessageHandler işlemeyi devre dışı bırakmak için cookie çağrısı:
services.AddHttpClient("configured-disable-automatic-cookies")
.ConfigurePrimaryHttpMessageHandler(() =>
{
return new HttpClientHandler()
{
UseCookies = false,
};
});
Günlüğe Kaydetme
Tüm istekler IHttpClientFactory için kayıt günlüğü iletileriyle oluşturulan istemciler. Varsayılan günlük iletilerini görmek için günlük yapılandırmasında uygun bilgi düzeyini etkinleştirin. İstek üst bilgilerini günlüğe kaydetme gibi ek günlükler yalnızca izleme düzeyinde dahil edilir.
Her istemci için kullanılan günlük kategorisi istemcinin adını içerir. Örneğin MyNamedClient adlı bir istemci iletileri "System.Net.Http.HttpClient" kategorisiyle günlüğe kaydeder. MyNamedClient. LogicalHandler". LogicalHandler ile sonekli iletiler, istek işleyicisi işlem hattının dışında oluşur. İstekte iletiler, işlem hattında diğer işleyiciler tarafından işlenmeden önce günlüğe kaydedilir. Yanıtta, diğer işlem hattı işleyicileri yanıtı aldıktan sonra iletiler günlüğe kaydedilir.
Günlük, istek işleyicisi işlem hattında da gerçekleşir. MyNamedClient örneğinde, bu iletiler "System.Net.Http.HttpClient" günlük kategorisiyle günlüğe kaydedilir. MyNamedClient. ClientHandler". İstek için, bu durum diğer tüm işleyiciler çalıştırktan ve istek gönderilmeden hemen önce gerçekleşir. Yanıtta bu günlük, işleyici işlem hattına geri dönmeden önce yanıtın durumunu içerir.
İşlem hattının dışında ve içinde günlüğe kaydetmeyi etkinleştirmek, diğer işlem hattı işleyicileri tarafından yapılan değişikliklerin incesini sağlar. Bu, istek üst bilgisinde veya yanıt durum kodunda yapılan değişiklikleri içerebilir.
İstemcinin adını günlük kategorisine dahil olmak, belirli adlandırılmış istemciler için günlük filtrelemeyi sağlar.
HttpMessageHandler'ı yapılandırma
İstemci tarafından kullanılan iç yapılandırmayı HttpMessageHandler denetlemeniz gerekebilir.
Adlandırılmış IHttpClientBuilder veya türe bağlı istemciler ekliyken bir döndürülür. Uzantı ConfigurePrimaryHttpMessageHandler yöntemi bir temsilci tanımlamak için kullanılabilir. Temsilci, bu istemci tarafından kullanılan birincili HttpMessageHandler oluşturmak ve yapılandırmak için kullanılır:
public void ConfigureServices(IServiceCollection services)
{
services.AddHttpClient("configured-inner-handler")
.ConfigurePrimaryHttpMessageHandler(() =>
{
return new HttpClientHandler()
{
AllowAutoRedirect = false,
UseDefaultCredentials = true
};
});
// Remaining code deleted for brevity.
Konsol uygulamasında IHttpClientFactory kullanma
Konsol uygulamasında aşağıdaki paket başvurularını projeye ekleyin:
Aşağıdaki örnekte:
- IHttpClientFactory , Genel Ana Bilgisayar'ın hizmet kapsayıcısı içinde kayıtlıdır.
MyService, hizmetten bir oluşturmak için kullanılan bir istemci fabrika örneğiHttpClientoluşturur.HttpClientbir web sayfasını almak için kullanılır.Mainhizmetin yöntemini yürütmek ve web sayfası içeriğinin ilkGetPage500 karakteri konsola yazmak için bir kapsam oluşturur.
using System;
using System.Net.Http;
using System.Threading.Tasks;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging;
class Program
{
static async Task<int> Main(string[] args)
{
var builder = new HostBuilder()
.ConfigureServices((hostContext, services) =>
{
services.AddHttpClient();
services.AddTransient<IMyService, MyService>();
}).UseConsoleLifetime();
var host = builder.Build();
try
{
var myService = host.Services.GetRequiredService<IMyService>();
var pageContent = await myService.GetPage();
Console.WriteLine(pageContent.Substring(0, 500));
}
catch (Exception ex)
{
var logger = host.Services.GetRequiredService<ILogger<Program>>();
logger.LogError(ex, "An error occurred.");
}
return 0;
}
public interface IMyService
{
Task<string> GetPage();
}
public class MyService : IMyService
{
private readonly IHttpClientFactory _clientFactory;
public MyService(IHttpClientFactory clientFactory)
{
_clientFactory = clientFactory;
}
public async Task<string> GetPage()
{
// Content from BBC One: Dr. Who website (©BBC)
var request = new HttpRequestMessage(HttpMethod.Get,
"https://www.bbc.co.uk/programmes/b006q2x0");
var client = _clientFactory.CreateClient();
var response = await client.SendAsync(request);
if (response.IsSuccessStatusCode)
{
return await response.Content.ReadAsStringAsync();
}
else
{
return $"StatusCode: {response.StatusCode}";
}
}
}
}
Üst bilgi yayma ara yazılımı
üst bilgi yayma, gelen istekten giden http istemci isteklerine HTTP üstbilgilerini yaymaya yönelik bir ASP.NET Core ara istemcindedir. Üst bilgi yaymayı kullanmak için:
Microsoft. AspNetCore. Headeryayma paketine başvurun.
Ara yazılımı ve
HttpClientiçinde yapılandırınStartup:public void ConfigureServices(IServiceCollection services) { services.AddControllers(); services.AddHttpClient("MyForwardingClient").AddHeaderPropagation(); services.AddHeaderPropagation(options => { options.Headers.Add("X-TraceId"); }); } public void Configure(IApplicationBuilder app, IWebHostEnvironment env) { if (env.IsDevelopment()) { app.UseDeveloperExceptionPage(); } app.UseHttpsRedirection(); app.UseHeaderPropagation(); app.UseRouting(); app.UseAuthorization(); app.UseEndpoints(endpoints => { endpoints.MapControllers(); }); }İstemci giden isteklerde yapılandırılan üst bilgileri içerir:
var client = clientFactory.CreateClient("MyForwardingClient"); var response = client.GetAsync(...);
Ek kaynaklar
Kirk Larkabağı, Steve Gordon, Glenn CONDRONve Ryan şimdi ak.
Bir IHttpClientFactory uygulamadaki örnekleri yapılandırmak ve oluşturmak için kayıt yapılabilir ve kullanılabilir HttpClient . IHttpClientFactory aşağıdaki avantajları sunar:
- , Mantıksal örnekleri adlandırmak ve yapılandırmak için merkezi bir konum sağlar
HttpClient. Örneğin, GitHub adlı bir istemci, GitHuberişmek için kaydedilebilir ve yapılandırılabilir. Varsayılan istemci, genel erişim için kaydedilebilir. - ' De işleyiciler temsilci seçme yoluyla giden ara yazılım kavramını daha da artırır
HttpClient. ' De işleyiciler temsilci atama avantajlarından faydalanmak için, Polya tabanlı bir ara yazılım için uzantılar sağlarHttpClient. - Temel örneklerin biriktirmesini ve ömrünü yönetir
HttpClientMessageHandler. Otomatik yönetim, yaşam sürelerini el ile yönetirken oluşan ortak DNS (etki alanı adı sistemi) sorunlarını önlerHttpClient. ILoggerFabrika tarafından oluşturulan istemciler aracılığıyla gönderilen tüm istekler için yapılandırılabilir bir günlüğe kaydetme deneyimi ekler (aracılığıyla).
Örnek kodu görüntüleyin veya indirin (nasıl indirilir).
Bu konu sürümündeki örnek kod, System.Text.Json http yanıtlarında döndürülen JSON içeriğinin serisini kaldırmak için kullanır. Ve kullanan örnekler için Json.NET ReadAsAsync<T> , bu konunun 2. x sürümünü seçmek üzere sürüm seçiciyi kullanın.
Tüketim desenleri
Bir uygulamada çeşitli yollar IHttpClientFactory kullanılabilir:
En iyi yaklaşım, uygulamanın gereksinimlerine bağlı olarak değişir.
Temel kullanım
IHttpClientFactory , çağırarak kaydedilebilir AddHttpClient :
public class Startup
{
public Startup(IConfiguration configuration)
{
Configuration = configuration;
}
public IConfiguration Configuration { get; }
public void ConfigureServices(IServiceCollection services)
{
services.AddHttpClient();
// Remaining code deleted for brevity.
IHttpClientFactory Bağımlılık ekleme (dı)kullanılarak bir istek yapılabilir. Aşağıdaki kod IHttpClientFactory bir örnek oluşturmak için kullanır HttpClient :
public class BasicUsageModel : PageModel
{
private readonly IHttpClientFactory _clientFactory;
public IEnumerable<GitHubBranch> Branches { get; private set; }
public bool GetBranchesError { get; private set; }
public BasicUsageModel(IHttpClientFactory clientFactory)
{
_clientFactory = clientFactory;
}
public async Task OnGet()
{
var request = new HttpRequestMessage(HttpMethod.Get,
"https://api.github.com/repos/dotnet/AspNetCore.Docs/branches");
request.Headers.Add("Accept", "application/vnd.github.v3+json");
request.Headers.Add("User-Agent", "HttpClientFactory-Sample");
var client = _clientFactory.CreateClient();
var response = await client.SendAsync(request);
if (response.IsSuccessStatusCode)
{
using var responseStream = await response.Content.ReadAsStreamAsync();
Branches = await JsonSerializer.DeserializeAsync
<IEnumerable<GitHubBranch>>(responseStream);
}
else
{
GetBranchesError = true;
Branches = Array.Empty<GitHubBranch>();
}
}
}
IHttpClientFactoryYukarıdaki örnekte olduğu gibi kullanmak, mevcut bir uygulamayı yeniden düzenleme için iyi bir yoldur. Kullanım hakkında hiçbir etkisi yoktur HttpClient . HttpClientVar olan bir uygulamada örneklerin oluşturulduğu yerlerde, bu oluşumların ' i çağrılarıyla değiştirin CreateClient .
Adlandırılmış istemciler
Adlandırılmış istemciler şu durumlarda iyi bir seçimdir:
- Uygulama birçok farklı kullanımı gerektirir
HttpClient. - Birçok
HttpClients farklı yapılandırmaya sahiptir.
Adlandırılmış için yapılandırma HttpClient , içinde kayıt sırasında belirtilebilir Startup.ConfigureServices :
services.AddHttpClient("github", c =>
{
c.BaseAddress = new Uri("https://api.github.com/");
// Github API versioning
c.DefaultRequestHeaders.Add("Accept", "application/vnd.github.v3+json");
// Github requires a user-agent
c.DefaultRequestHeaders.Add("User-Agent", "HttpClientFactory-Sample");
});
İstemcinin yapılandırıldığı önceki kodda:
- Temel adres
https://api.github.com/. - GitHub apı ile çalışmak için iki üst bilgi gereklidir.
CreateClient
Her zaman CreateClient çağrılır:
- Yeni bir örneği
HttpClientoluşturulur. - Yapılandırma eylemi çağrılır.
Adlandırılmış bir istemci oluşturmak için adını içine geçirin CreateClient :
public class NamedClientModel : PageModel
{
private readonly IHttpClientFactory _clientFactory;
public IEnumerable<GitHubPullRequest> PullRequests { get; private set; }
public bool GetPullRequestsError { get; private set; }
public bool HasPullRequests => PullRequests.Any();
public NamedClientModel(IHttpClientFactory clientFactory)
{
_clientFactory = clientFactory;
}
public async Task OnGet()
{
var request = new HttpRequestMessage(HttpMethod.Get,
"repos/dotnet/AspNetCore.Docs/pulls");
var client = _clientFactory.CreateClient("github");
var response = await client.SendAsync(request);
if (response.IsSuccessStatusCode)
{
using var responseStream = await response.Content.ReadAsStreamAsync();
PullRequests = await JsonSerializer.DeserializeAsync
<IEnumerable<GitHubPullRequest>>(responseStream);
}
else
{
GetPullRequestsError = true;
PullRequests = Array.Empty<GitHubPullRequest>();
}
}
}
Yukarıdaki kodda, isteğin bir ana bilgisayar adı belirtmesi gerekmez. İstemci için yapılandırılan taban adresi kullanıldığından, kod yalnızca yolu geçirebilir.
Yazılan istemciler
Yazılan istemciler:
- Dizeleri anahtar olarak kullanma gereksinimi olmadan, adlandırılmış istemcilerle aynı özellikleri sağlayın.
- İstemcileri tükettiren IntelliSense ve derleyici yardımı sağlar.
- Yapılandırmak ve belirli bir ile etkileşimde bulunmak için tek bir konum belirtin
HttpClient. Örneğin, tek bir türü belirtilmiş istemci kullanılabilir:- Tek bir arka uç uç noktası için.
- Uç nokta ile ilgili tüm mantığı kapsüllemek için.
- DI ile birlikte çalışın ve uygulamada gerektiğinde eklenebilir.
Türü belirtilmiş istemci HttpClient , oluşturucusunda bir parametreyi kabul eder:
public class GitHubService
{
public HttpClient Client { get; }
public GitHubService(HttpClient client)
{
client.BaseAddress = new Uri("https://api.github.com/");
// GitHub API versioning
client.DefaultRequestHeaders.Add("Accept",
"application/vnd.github.v3+json");
// GitHub requires a user-agent
client.DefaultRequestHeaders.Add("User-Agent",
"HttpClientFactory-Sample");
Client = client;
}
public async Task<IEnumerable<GitHubIssue>> GetAspNetDocsIssues()
{
var response = await Client.GetAsync(
"/repos/dotnet/AspNetCore.Docs/issues?state=open&sort=created&direction=desc");
response.EnsureSuccessStatusCode();
using var responseStream = await response.Content.ReadAsStreamAsync();
return await JsonSerializer.DeserializeAsync
<IEnumerable<GitHubIssue>>(responseStream);
}
}
Ingilizce dışındaki dillere çevrilmiş kod açıklamalarını görmek isterseniz, Bu GitHub tartışma sorununubize tanıyın.
Yukarıdaki kodda:
- Yapılandırma, yazılan istemciye taşınır.
HttpClientNesne bir ortak özellik olarak sunulur.
İşlevselliği kullanıma sunan, API 'ye özgü Yöntemler oluşturulabilir HttpClient . Örneğin, GetAspNetDocsIssues yöntemi açık sorunları almak için kodu kapsüller.
Aşağıdaki kod, AddHttpClient Startup.ConfigureServices türü belirtilmiş bir istemci sınıfını kaydetmek için ' de çağırır:
services.AddHttpClient<GitHubService>();
Yazılan istemci, DI ile geçici olarak kaydedilir. Yukarıdaki kodda AddHttpClient GitHubService geçici bir hizmet olarak kaydedilir. Bu kayıt, için bir fabrika yöntemi kullanır:
HttpClientörneği oluşturun.- Örneğini oluşturucusuna geçirerek bir örneğini oluşturun
GitHubServiceHttpClient.
Yazılan istemci doğrudan eklenebilir ve tüketilebilir:
public class TypedClientModel : PageModel
{
private readonly GitHubService _gitHubService;
public IEnumerable<GitHubIssue> LatestIssues { get; private set; }
public bool HasIssue => LatestIssues.Any();
public bool GetIssuesError { get; private set; }
public TypedClientModel(GitHubService gitHubService)
{
_gitHubService = gitHubService;
}
public async Task OnGet()
{
try
{
LatestIssues = await _gitHubService.GetAspNetDocsIssues();
}
catch(HttpRequestException)
{
GetIssuesError = true;
LatestIssues = Array.Empty<GitHubIssue>();
}
}
}
Türü belirtilmiş bir istemcinin yapılandırması Startup.ConfigureServices , türü belirlenmiş istemcinin Oluşturucusu yerine kayıt sırasında belirtilebilir:
services.AddHttpClient<RepoService>(c =>
{
c.BaseAddress = new Uri("https://api.github.com/");
c.DefaultRequestHeaders.Add("Accept", "application/vnd.github.v3+json");
c.DefaultRequestHeaders.Add("User-Agent", "HttpClientFactory-Sample");
});
, HttpClient Türü belirlenmiş bir istemci içinde kapsüllenebilir. Bunu bir özellik olarak göstermek yerine, örneği dahili olarak çağıran bir yöntem tanımlayın HttpClient :
public class RepoService
{
// _httpClient isn't exposed publicly
private readonly HttpClient _httpClient;
public RepoService(HttpClient client)
{
_httpClient = client;
}
public async Task<IEnumerable<string>> GetRepos()
{
var response = await _httpClient.GetAsync("aspnet/repos");
response.EnsureSuccessStatusCode();
using var responseStream = await response.Content.ReadAsStreamAsync();
return await JsonSerializer.DeserializeAsync
<IEnumerable<string>>(responseStream);
}
}
Yukarıdaki kodda, HttpClient bir özel alanda depolanır. Öğesine erişimi, HttpClient genel yöntemi tarafından yapılır GetRepos .
Oluşturulan istemciler
IHttpClientFactory , yeniden sığdırmagibi üçüncü taraf kitaplıklarla birlikte kullanılabilir. Yeniden sığdırma, .NET için bir REST kitaplığıdır. REST API 'Leri canlı arabirimlere dönüştürür. Arabirim bir uygulama, RestService HttpClient dış http çağrıları yapmak için kullanılarak tarafından dinamik olarak oluşturulur.
Bir arabirim ve yanıt, dış API 'yi ve yanıtını temsil edecek şekilde tanımlanır:
public interface IHelloClient
{
[Get("/helloworld")]
Task<Reply> GetMessageAsync();
}
public class Reply
{
public string Message { get; set; }
}
Türü belirlenmiş bir istemci eklenebilir, uygulamayı oluşturmak için yeniden sığdırma kullanımı kullanılabilir:
public void ConfigureServices(IServiceCollection services)
{
services.AddHttpClient("hello", c =>
{
c.BaseAddress = new Uri("http://localhost:5000");
})
.AddTypedClient(c => Refit.RestService.For<IHelloClient>(c));
services.AddControllers();
}
Tanımlı arabirim, gereken yerde, mak ve Refit tarafından sağlanmış uygulama ile kullanılabilir.
[ApiController]
public class ValuesController : ControllerBase
{
private readonly IHelloClient _client;
public ValuesController(IHelloClient client)
{
_client = client;
}
[HttpGet("/")]
public async Task<ActionResult<Reply>> Index()
{
return await _client.GetMessageAsync();
}
}
GÖNDERI, PUT ve DELETE isteklerini oluşturma
Yukarıdaki örneklerde, tüm HTTP istekleri GET HTTP fiilini kullanır. HttpClient , aşağıdakiler de dahil olmak üzere diğer HTTP fiillerini de destekler:
- POST
- PUT
- DELETE
- DÜZELTMESI
Desteklenen HTTP fiillerinin tüm 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(TodoItem todoItem)
{
var todoItemJson = new StringContent(
JsonSerializer.Serialize(todoItem, _jsonSerializerOptions),
Encoding.UTF8,
"application/json");
using var httpResponse =
await _httpClient.PostAsync("/api/TodoItems", todoItemJson);
httpResponse.EnsureSuccessStatusCode();
}
Yukarıdaki kodda, CreateItemAsync yöntemi:
TodoItemParametresini kullanarak JSON için parametreyi seri hale getirirSystem.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 SaveItemAsync(TodoItem todoItem)
{
var todoItemJson = new StringContent(
JsonSerializer.Serialize(todoItem),
Encoding.UTF8,
"application/json");
using var httpResponse =
await _httpClient.PutAsync($"/api/TodoItems/{todoItem.Id}", todoItemJson);
httpResponse.EnsureSuccessStatusCode();
}
Yukarıdaki kod, POST örneğine çok benzer. SaveItemAsyncYöntemi yerine çağırır PutAsync PostAsync .
Aşağıdaki örnekte bir HTTP SILME isteği gösterilmektedir:
public async Task DeleteItemAsync(long itemId)
{
using var httpResponse =
await _httpClient.DeleteAsync($"/api/TodoItems/{itemId}");
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 ..
Giden istek ara yazılımı
HttpClient , giden HTTP istekleri için birlikte bağlanabilen işleyicileri temsilci seçme kavramıdır. IHttpClientFactory:
Her bir adlandırılmış istemci için uygulanacak işleyiciler tanımlamayı basitleştirir.
Bir giden istek ara yazılım işlem hattı oluşturmak için birden çok işleyicinin kaydedilmesini ve zincirleme kullanımını destekler. Bu işleyicilerin her biri, giden istekten önce ve sonra iş gerçekleştirebilir. Bu model:
- ASP.NET Core gelen ara yazılım ardışık düzenine benzerdir.
- , HTTP istekleri etrafında çapraz kesme sorunlarını yönetmek için bir mekanizma sağlar, örneğin:
- önbelleği
- hata işleme
- getir
- günlüğe kaydetme
Temsilci seçme işleyicisi oluşturmak için:
- Türet DelegatingHandler .
- Geçersiz kıl SendAsync . İsteği ardışık düzen içindeki bir sonraki işleyiciye geçirmeden önce kodu yürütün:
public class ValidateHeaderHandler : DelegatingHandler
{
protected override async Task<HttpResponseMessage> SendAsync(
HttpRequestMessage request,
CancellationToken cancellationToken)
{
if (!request.Headers.Contains("X-API-KEY"))
{
return new HttpResponseMessage(HttpStatusCode.BadRequest)
{
Content = new StringContent(
"You must supply an API key header called X-API-KEY")
};
}
return await base.SendAsync(request, cancellationToken);
}
}
Yukarıdaki kod, üstbilginin istekte olup olmadığını denetler X-API-KEY . X-API-KEYEksikse, BadRequest döndürülür.
İçin yapılandırmasına birden fazla işleyici eklenebilir HttpClient Microsoft.Extensions.DependencyInjection.HttpClientBuilderExtensions.AddHttpMessageHandler :
public void ConfigureServices(IServiceCollection services)
{
services.AddTransient<ValidateHeaderHandler>();
services.AddHttpClient("externalservice", c =>
{
// Assume this is an "external" service which requires an API KEY
c.BaseAddress = new Uri("https://localhost:5001/");
})
.AddHttpMessageHandler<ValidateHeaderHandler>();
// Remaining code deleted for brevity.
Yukarıdaki kodda,, ValidateHeaderHandler dı ile kaydedilir. Kaydedildikten sonra, AddHttpMessageHandler işleyicinin türü geçirerek, çağrılabilir.
Birden çok işleyici, yürütülmesi gereken sırayla kaydedilebilir. Her işleyici, son isteği çalıştırana kadar sonraki işleyiciyi sarmalar HttpClientHandler :
services.AddTransient<SecureRequestHandler>();
services.AddTransient<RequestDataHandler>();
services.AddHttpClient("clientwithhandlers")
// This handler is on the outside and called first during the
// request, last during the response.
.AddHttpMessageHandler<SecureRequestHandler>()
// This handler is on the inside, closest to the request being
// sent.
.AddHttpMessageHandler<RequestDataHandler>();
Giden istek ara ortamında DI kullanma
IHttpClientFactoryYeni bir temsilci seçme işleyicisi oluşturduğunda, işleyicinin Oluşturucu parametrelerini karşılamak IÇIN dı kullanır. IHttpClientFactory Her işleyici için ayrı bir dı kapsamı oluşturur ve bu, bir işleyici kapsamlı bir hizmeti tükettiği zaman ortaya çıkmasına neden olabilir.
Örneğin, bir görevi tanımlayıcı ile bir işlem olarak temsil eden aşağıdaki arabirimi ve uygulamasını göz önünde bulundurun OperationId :
public interface IOperationScoped
{
string OperationId { get; }
}
public class OperationScoped : IOperationScoped
{
public string OperationId { get; } = Guid.NewGuid().ToString()[^4..];
}
Adından da anlaşılacağı gibi, IOperationScoped kapsamlı bir yaşam süresi kullanılarak dı ile kaydedilir:
public void ConfigureServices(IServiceCollection services)
{
services.AddDbContext<TodoContext>(options =>
options.UseInMemoryDatabase("TodoItems"));
services.AddHttpContextAccessor();
services.AddHttpClient<TodoClient>((sp, httpClient) =>
{
var httpRequest = sp.GetRequiredService<IHttpContextAccessor>().HttpContext.Request;
// For sample purposes, assume TodoClient is used in the context of an incoming request.
httpClient.BaseAddress = new Uri(UriHelper.BuildAbsolute(httpRequest.Scheme,
httpRequest.Host, httpRequest.PathBase));
httpClient.Timeout = TimeSpan.FromSeconds(5);
});
services.AddScoped<IOperationScoped, OperationScoped>();
services.AddTransient<OperationHandler>();
services.AddTransient<OperationResponseHandler>();
services.AddHttpClient("Operation")
.AddHttpMessageHandler<OperationHandler>()
.AddHttpMessageHandler<OperationResponseHandler>()
.SetHandlerLifetime(TimeSpan.FromSeconds(5));
services.AddControllers();
services.AddRazorPages();
}
Aşağıdaki temsilci işleyicisi, IOperationScoped X-OPERATION-ID giden istek için üst bilgiyi ayarlamak için kullanır ve kullanır:
public class OperationHandler : DelegatingHandler
{
private readonly IOperationScoped _operationService;
public OperationHandler(IOperationScoped operationScoped)
{
_operationService = operationScoped;
}
protected async override Task<HttpResponseMessage> SendAsync(
HttpRequestMessage request, CancellationToken cancellationToken)
{
request.Headers.Add("X-OPERATION-ID", _operationService.OperationId);
return await base.SendAsync(request, cancellationToken);
}
}
HttpRequestsSample İndir] /Operation sayfasında, sayfasına gidin ve sayfayı yenileyin. İstek kapsamı değeri her istek için değişir, ancak işleyici kapsam değeri yalnızca her 5 saniyede bir değişir.
İşleyiciler herhangi bir kapsamın hizmetlerine bağlı olabilir. İşleyicilerin bağımlı olduğu hizmetler, işleyicinin elden çıkarılmasıyla kaldırılır.
İleti işleyicileriyle istek başına durumu paylaşmak için aşağıdaki yaklaşımlardan birini kullanın:
- HttpRequestMessage. Propertieskullanarak işleyicide veri geçirin.
- IHttpContextAccessorGeçerli isteğe erişmek için kullanın.
- AsyncLocal<T>Verileri geçirmek için özel bir depolama nesnesi oluşturun.
Polly tabanlı işleyiciler kullanın
IHttpClientFactory üçüncü taraf kitaplığı Pollyile tümleşir. Polly, .NET için kapsamlı bir esnekliği ve geçici hata işleme kitaplığıdır. Geliştiricilerin yeniden deneme, devre kesici, zaman aşımı, Bulkbaş yalıtımı, akıcı ve iş parçacığı açısından güvenli bir şekilde geri dönüş gibi ilkeler almasına olanak tanır.
Uzantı yöntemleri, yapılandırılmış örneklerle Polly ilkelerin kullanımını etkinleştirmek için sağlanır HttpClient . Polly uzantıları, istemcilere Polly tabanlı işleyiciler eklemeyi destekler. polly, Microsoft. Extensions. Http. polly NuGet paketini gerektirir.
Geçici hataları işle
Hatalar genellikle dış HTTP çağrıları geçici olduğunda oluşur. AddTransientHttpErrorPolicy geçici hataları işlemek için bir ilkenin tanımlanmasını sağlar. AddTransientHttpErrorPolicyAşağıdaki yanıtları işleyecek şekilde yapılandırılan ilkeler:
- HttpRequestException
- HTTP 5xx
- HTTP 408
AddTransientHttpErrorPolicy``PolicyBuilderolası bir geçici hatayı temsil eden hataları işlemek için yapılandırılmış bir nesneye erişim sağlar:
public void ConfigureServices(IServiceCollection services)
{
services.AddHttpClient<UnreliableEndpointCallerService>()
.AddTransientHttpErrorPolicy(p =>
p.WaitAndRetryAsync(3, _ => TimeSpan.FromMilliseconds(600)));
// Remaining code deleted for brevity.
Yukarıdaki kodda bir WaitAndRetryAsync ilke tanımlanmıştır. Başarısız istekler, denemeler arasındaki 600 MS gecikmeyle en fazla üç kez yeniden denenir.
Dinamik olarak ilke seçme
Uzantı yöntemleri, örneğin, Polly tabanlı işleyiciler eklemek için sağlanır AddPolicyHandler . Aşağıdaki AddPolicyHandler aşırı yükleme, hangi ilkenin uygulanacağını belirlemek için isteği inceler:
var timeout = Policy.TimeoutAsync<HttpResponseMessage>(
TimeSpan.FromSeconds(10));
var longTimeout = Policy.TimeoutAsync<HttpResponseMessage>(
TimeSpan.FromSeconds(30));
services.AddHttpClient("conditionalpolicy")
// Run some code to select a policy based on the request
.AddPolicyHandler(request =>
request.Method == HttpMethod.Get ? timeout : longTimeout);
Yukarıdaki kodda, giden istek bir HTTP GET ise, 10 saniyelik bir zaman aşımı uygulanır. Diğer HTTP yöntemleri için, 30 saniyelik bir zaman aşımı kullanılır.
Birden çok Polly işleyici ekleme
Polly ilkeleri iç içe almak yaygın bir şekilde yapılır:
services.AddHttpClient("multiplepolicies")
.AddTransientHttpErrorPolicy(p => p.RetryAsync(3))
.AddTransientHttpErrorPolicy(
p => p.CircuitBreakerAsync(5, TimeSpan.FromSeconds(30)));
Yukarıdaki örnekte:
- İki işleyici eklenir.
- İlk işleyici, AddTransientHttpErrorPolicy yeniden deneme ilkesi eklemek için kullanır. Başarısız istekler en fazla üç kez yeniden denenir.
- İkinci
AddTransientHttpErrorPolicyçağrı bir devre kesici ilkesi ekler. 5 başarısız girişim sıralı olarak gerçekleşirse, daha fazla dış istek 30 saniye boyunca engellenir. Devre kesici ilkeleri durum bilgisi vardır. Bu istemci aracılığıyla yapılan tüm çağrılar aynı devre durumunu paylaşır.
Polly kayıt defterinden ilke ekleme
Düzenli olarak kullanılan ilkeleri yönetmeye yönelik bir yaklaşım, bunları bir kez tanımlayıp bir ile kaydetmektir PolicyRegistry .
Aşağıdaki kodda:
- "Normal" ve "uzun" ilkeler eklenmiştir.
- AddPolicyHandlerFromRegistry kayıt defterinden "normal" ve "uzun" ilkeleri ekler.
public void ConfigureServices(IServiceCollection services)
{
var timeout = Policy.TimeoutAsync<HttpResponseMessage>(
TimeSpan.FromSeconds(10));
var longTimeout = Policy.TimeoutAsync<HttpResponseMessage>(
TimeSpan.FromSeconds(30));
var registry = services.AddPolicyRegistry();
registry.Add("regular", timeout);
registry.Add("long", longTimeout);
services.AddHttpClient("regularTimeoutHandler")
.AddPolicyHandlerFromRegistry("regular");
services.AddHttpClient("longTimeoutHandler")
.AddPolicyHandlerFromRegistry("long");
// Remaining code deleted for brevity.
Ve daha fazla tümleştirme hakkında daha fazla bilgi için IHttpClientFactory bkz. Polly wiki.
HttpClient ve ömür yönetimi
HttpClientHer çağrıldığında yeni bir örnek döndürülür CreateClient IHttpClientFactory . HttpMessageHandlerAdlandırılmış istemci başına oluşturulur. Fabrika, örneklerin yaşam sürelerini yönetir HttpMessageHandler .
IHttpClientFactory``HttpMessageHandlerkaynak tüketimini azaltmak için fabrika tarafından oluşturulan örnekleri havuzlar. Bir HttpMessageHandler örnek, süresi dolmamışsa yeni bir örnek oluştururken havuzdan yeniden kullanılabilir HttpClient .
Her işleyici genellikle kendi temel HTTP bağlantılarını yönettiğinden, işleyicilerin havuzlaması 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 (etki alanı adı sistemi) değişikliklerine yeniden davranmasını engelleyebilir.
Varsayılan işleyici ömrü iki dakikadır. Varsayılan değer, adlandırılmış istemci temelinde geçersiz kılınabilir:
public void ConfigureServices(IServiceCollection services)
{
services.AddHttpClient("extendedhandlerlifetime")
.SetHandlerLifetime(TimeSpan.FromMinutes(5));
// Remaining code deleted for brevity.
HttpClient örnekler genellikle aktiften çıkarma gerektirmeyen .NET nesneleri olarak kabul edilebilir. Çı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 .
Ihttpclientfactory alternatifleri
IHttpClientFactoryDı etkin bir uygulamada kullanmak şunları önler:
- Havuz örneklerine göre kaynak tükenmesi sorunları
HttpMessageHandler. - Düzenli aralıklarla örnekleri geçirerek eski DNS sorunları
HttpMessageHandler.
Uzun süreli bir örnek kullanarak önceki sorunları çözmenin alternatif yolları vardır SocketsHttpHandler .
SocketsHttpHandlerUygulamanın başladığı zaman bir örneği oluşturun ve uygulamanın ömrü boyunca kullanın.- PooledConnectionLifetimeDNS yenileme süreleri temelinde uygun bir değere yapılandırın.
HttpClientGerektiğinde örnek oluşturunnew HttpClient(handler, disposeHandler: false).
Yukarıdaki yaklaşımlar, IHttpClientFactory benzer bir şekilde çözen kaynak yönetimi sorunlarını çözer.
- ,
SocketsHttpHandlerÖrnekleri arasında bağlantıları paylaşırHttpClient. Bu paylaşım, yuva azalmasına engel olur. SocketsHttpHandlerBağlantıları,PooledConnectionLifetimeeski DNS sorunlarından kaçınmak için öğesine göre döngüler.
Cookiemalar
Havuza alınmış HttpMessageHandler örnekler, CookieContainer paylaşılan nesneler ile sonuçlanır. Beklenmeyen CookieContainer nesne paylaşımı genellikle hatalı kodla sonuçlanır. S gerektiren uygulamalar için cookie şunlardan birini göz önünde bulundurun:
- Otomatik işlemeyi devre dışı bırakma cookie
- Önlemenin
IHttpClientFactory
ConfigurePrimaryHttpMessageHandlerOtomatik işlemeyi devre dışı bırakmak için çağırın cookie :
services.AddHttpClient("configured-disable-automatic-cookies")
.ConfigurePrimaryHttpMessageHandler(() =>
{
return new HttpClientHandler()
{
UseCookies = false,
};
});
Günlüğe Kaydetme
IHttpClientFactoryTüm istekler için kayıt günlüğü iletileri aracılığıyla oluşturulan istemciler. Varsayılan günlük iletilerini görmek için günlük yapılandırmasında uygun bilgi düzeyini etkinleştirin. İstek üst bilgilerinin günlüğe kaydedilmesi gibi ek Günlükler yalnızca izleme düzeyinde yer alır.
Her istemci için kullanılan günlük kategorisi, istemcinin adını içerir. Örneğin, Mynamedclient adlı bir istemci, "System .net. http. HttpClient" kategorisine sahip iletileri günlüğe kaydeder. Mynamedclient. LogicalHandler ". Logicalhandler ile düzeltilen iletiler istek işleyicisi ardışık düzeni dışında oluşur. İstekte, işlem hattındaki diğer işleyiciler işlenmeden önce iletiler günlüğe kaydedilir. Yanıtta, tüm diğer işlem hattı işleyicileri yanıtı aldıktan sonra iletiler günlüğe kaydedilir.
Günlüğe kaydetme, istek işleyicisi ardışık düzeni içinde de gerçekleşir. Mynamedclient örneğinde, bu Iletiler "System .net. http. HttpClient" günlük kategorisiyle günlüğe kaydedilir. Mynamedclient. ClientHandler ". İstek için bu, tüm diğer işleyiciler çalıştırıldıktan sonra ve istek gönderilmeden hemen önce gerçekleşir. Yanıtta, bu günlüğe kaydetme, işleyicinin işleyici işlem hattı üzerinden geri geçirmeden önce yanıtın durumunu içerir.
İşlem hattının dışında ve içinde günlüğe kaydetmenin etkinleştirilmesi, diğer işlem hattı işleyicileri tarafından yapılan değişikliklerin incelemesini etkinleştirir. Bu, istek üst bilgilerinde veya yanıt durum kodunda yapılan değişiklikleri içerebilir.
İstemcinin adını log kategorisinde da içermek, belirli adlandırılmış istemciler için günlük filtrelemeyi sunar.
HttpMessageHandler 'ı yapılandırma
İ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. ConfigurePrimaryHttpMessageHandlerGenişletme yöntemi bir temsilciyi tanımlamak için kullanılabilir. Temsilci, HttpMessageHandler Bu istemci tarafından kullanılan birincili oluşturmak ve yapılandırmak için kullanılır:
public void ConfigureServices(IServiceCollection services)
{
services.AddHttpClient("configured-inner-handler")
.ConfigurePrimaryHttpMessageHandler(() =>
{
return new HttpClientHandler()
{
AllowAutoRedirect = false,
UseDefaultCredentials = true
};
});
// Remaining code deleted for brevity.
Konsol uygulamasında ıhttpclientfactory kullanma
Konsol uygulamasında, aşağıdaki paket başvurularını projeye ekleyin:
Aşağıdaki örnekte:
- IHttpClientFactory , genel konağın hizmet kapsayıcısına kaydedilir.
MyServicehizmetinden bir istemci fabrikası örneği oluştururHttpClient.HttpClient, bir Web sayfasını almak için kullanılır.Mainhizmetin yöntemini yürütmek için bir kapsam oluştururGetPageve Web sayfası içeriğinin ilk 500 karakterini konsola yazar.
using System;
using System.Net.Http;
using System.Threading.Tasks;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging;
class Program
{
static async Task<int> Main(string[] args)
{
var builder = new HostBuilder()
.ConfigureServices((hostContext, services) =>
{
services.AddHttpClient();
services.AddTransient<IMyService, MyService>();
}).UseConsoleLifetime();
var host = builder.Build();
try
{
var myService = host.Services.GetRequiredService<IMyService>();
var pageContent = await myService.GetPage();
Console.WriteLine(pageContent.Substring(0, 500));
}
catch (Exception ex)
{
var logger = host.Services.GetRequiredService<ILogger<Program>>();
logger.LogError(ex, "An error occurred.");
}
return 0;
}
public interface IMyService
{
Task<string> GetPage();
}
public class MyService : IMyService
{
private readonly IHttpClientFactory _clientFactory;
public MyService(IHttpClientFactory clientFactory)
{
_clientFactory = clientFactory;
}
public async Task<string> GetPage()
{
// Content from BBC One: Dr. Who website (©BBC)
var request = new HttpRequestMessage(HttpMethod.Get,
"https://www.bbc.co.uk/programmes/b006q2x0");
var client = _clientFactory.CreateClient();
var response = await client.SendAsync(request);
if (response.IsSuccessStatusCode)
{
return await response.Content.ReadAsStringAsync();
}
else
{
return $"StatusCode: {response.StatusCode}";
}
}
}
}
Üst bilgi yayma ara yazılımı
üst bilgi yayma, gelen istekten giden http istemci isteklerine HTTP üstbilgilerini yaymaya yönelik bir ASP.NET Core ara istemcindedir. Üst bilgi yaymayı kullanmak için:
Microsoft. AspNetCore. Headeryayma paketine başvurun.
Ara yazılımı ve
HttpClientiçinde yapılandırınStartup:public void ConfigureServices(IServiceCollection services) { services.AddControllers(); services.AddHttpClient("MyForwardingClient").AddHeaderPropagation(); services.AddHeaderPropagation(options => { options.Headers.Add("X-TraceId"); }); } public void Configure(IApplicationBuilder app, IWebHostEnvironment env) { if (env.IsDevelopment()) { app.UseDeveloperExceptionPage(); } app.UseHttpsRedirection(); app.UseHeaderPropagation(); app.UseRouting(); app.UseAuthorization(); app.UseEndpoints(endpoints => { endpoints.MapControllers(); }); }İstemci giden isteklerde yapılandırılan üst bilgileri içerir:
var client = clientFactory.CreateClient("MyForwardingClient"); var response = client.GetAsync(...);