Požadavky HTTP můžete provádět pomocí IHttpClientFactory v ASP.NET Core
Od Gordona Užkina, Steve Gordona, Thena Condronaa Ryana Nowaka.
Objekt IHttpClientFactory je možné zaregistrovat a použít ke konfiguraci HttpClient a vytváření instancí v aplikaci. IHttpClientFactory nabízí následující výhody:
- Poskytuje centrální umístění pro pojmenování a konfiguraci
HttpClientlogických instancí. Například klient s názvem github může být zaregistrovaný a nakonfigurovaný pro přístup k GitHub. Pro obecný přístup je možné zaregistrovat výchozího klienta. - Kodifikuje koncept odchozího middlewaru prostřednictvím delegování obslužných rutin v
HttpClient. Poskytuje rozšíření middlewaru založeného na Polly, která využívají delegování obslužných rutin vHttpClientnástroji . - Spravuje sdružování a životnost základních
HttpClientMessageHandlerinstancí. Automatická správa zabraňuje běžným problémům se systémem DNS (Domain Name System), ke kterým dochází při ruční správěHttpClientživotnosti. - Přidá konfigurovatelné prostředí protokolování (prostřednictvím ) pro všechny požadavky odeslané
ILoggerprostřednictvím klientů vytvořených objektem pro vytváření.
Zobrazení nebo stažení ukázkového kódu (stažení).
Vzorový kód v této verzi tématu používá System.Text.Json k deserializaci obsahu JSON vráceného v odpovědích HTTP. Pro ukázky, které používají a , použijte selektor verzí k výběru verze Json.NET ReadAsAsync<T> 2.x tohoto tématu.
Spotřeby
V aplikaci IHttpClientFactory je možné použít několik způsobů:
Nejlepší přístup závisí na požadavcích aplikace.
Základní použití
IHttpClientFactory je možné zaregistrovat voláním 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.
O IHttpClientFactory objekt je možné požádat pomocí injektáže závislostí (DI). Následující kód používá IHttpClientFactory k vytvoření HttpClient instance :
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>();
}
}
}
Použití IHttpClientFactory příkazu like v předchozím příkladu je dobrým způsobem, jak refaktorovat existující aplikaci. Nemá žádný vliv na způsob HttpClient použití. Na místech, kde jsou instance vytvořené v existující aplikaci, nahraďte tyto HttpClient výskyty voláním CreateClient .
Pojmenovaní klienti
Pojmenovaní klienti jsou dobrou volbou v případě, že:
- Aplikace vyžaduje mnoho různých použití
HttpClient. - Mnoho
HttpClientz nich má jinou konfiguraci.
Konfiguraci pojmenovaného HttpClient objektu je možné zadat během registrace v Startup.ConfigureServices nástroji :
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");
});
V předchozím kódu je klient nakonfigurovaný s:
- Základní adresa
https://api.github.com/. - Dvě hlavičky potřebné pro práci s rozhraním GITHUB API.
CreateClient
Pokaždé CreateClient se volá:
- Vytvoří se nová
HttpClientinstance . - Volá se konfigurační akce.
Pokud chcete vytvořit pojmenovaného klienta, předejte jeho název do 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>();
}
}
}
V předchozím kódu nemusí požadavek zadat název hostitele. Kód může předat pouze cestu, protože se používá základní adresa nakonfigurovaná pro klienta.
Typové klienty
Typové klienty:
- Poskytovat stejné funkce jako pojmenovaní klienti bez nutnosti používat řetězce jako klíče.
- Poskytuje IntelliSense a nápovědu kompilátoru při využívání klientů.
- Zadejte jedno umístění pro konfiguraci a interakci s konkrétním
HttpClient. Může se například použít jeden typovaný klient:- Pro jeden koncový bod back-endu.
- Zapouzdření veškeré logiky, která se zabývá koncovým bodem.
- Pracujte s injekvencí injekvencí, kde je to v aplikaci potřeba.
Typový klient přijímá parametr HttpClient ve svém konstruktoru:
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");
}
}
V předchozím kódu:
- Konfigurace se přesune do typu klienta.
- Objekt
HttpClientje vystavený jako veřejná vlastnost.
Je možné vytvořit metody specifické pro rozhraní API, které zpřístupňuje HttpClient funkce. Například metoda GetAspNetDocsIssues zapouzdřuje kód pro načtení otevřených problémů.
Následující kód volá AddHttpClient v Startup.ConfigureServices pro registraci typové třídy klienta:
services.AddHttpClient<GitHubService>();
Typový klient je zaregistrovaný jako přechodný u diody. V předchozím kódu se AddHttpClient zaregistruje GitHubService jako přechodná služba. Tato registrace používá metodu továrny k:
- Vytvořte instanci
HttpClient. - Vytvořte instanci
GitHubService, která instanci předáHttpClientsvému konstruktoru.
Typovaného klienta je možné vloženého a spotřebovávat přímo:
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>();
}
}
}
Konfiguraci pro zadaného klienta je možné zadat během registrace v , a ne v Startup.ConfigureServices konstruktoru zadaného klienta:
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");
});
Může HttpClient být zapouzdřen v rámci typ klienta. Místo toho, aby se vystavil jako vlastnost, definujte metodu, která HttpClient interně volá instanci:
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);
}
}
V předchozím kódu je HttpClient objekt uložen v soukromém poli. Přístup k HttpClient je pomocí veřejné GetRepos metody.
Vygenerovaní klienti
IHttpClientFactory je možné použít v kombinaci s knihovnami třetích stran, jako je například Přeučovat. Refit je knihovna REST pro .NET. Převádí rozhraní REST API na živá rozhraní. Implementace rozhraní je generována dynamicky pomocí RestService , k provedení externích volání HttpClient HTTP.
Rozhraní a odpověď jsou definovány tak, aby představovaly externí rozhraní API a jeho odpověď:
public interface IHelloClient
{
[Get("/helloworld")]
Task<Reply> GetMessageAsync();
}
public class Reply
{
public string Message { get; set; }
}
Typovaný klient je možné přidat pomocí příkazu Refit pro vygenerování implementace:
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();
}
Definované rozhraní je možné v případě potřeby využívat s implementací, kterou poskytuje DI a Refit:
[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();
}
}
Požadavky POST, PUT a DELETE
V předchozích příkladech používají všechny požadavky HTTP příkaz GET HTTP. HttpClient podporuje také další příkazy HTTP, včetně následujících:
- POST
- PUT
- DELETE
- OPRAVA
Úplný seznam podporovaných operací HTTP najdete v tématu HttpMethod .
Následující příklad ukazuje, jak vytvořit požadavek HTTP POST:
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();
}
V předchozím kódu metoda CreateItemAsync :
- Serializuje parametr
TodoItemdo formátu JSON pomocíSystem.Text.Json. To používá instanci JsonSerializerOptions ke konfiguraci procesu serializace. - Vytvoří instanci pro StringContent zabalení serializovaného formátu JSON pro odeslání v textu požadavku HTTP.
- Zavolá PostAsync metodu , která odešle obsah JSON na zadanou adresu URL. Toto je relativní adresa URL, která se přidá do HttpClient.BaseAddress.
- Zavolá EnsureSuccessStatusCode metodu , která vyvolá výjimku, pokud stavový kód odpovědi neznačí úspěch.
HttpClient podporuje také další typy obsahu. Příklad: MultipartContent a StreamContent. Úplný seznam podporovaných obsahu najdete v tématu HttpContent .
Následující příklad ukazuje požadavek HTTP PUT:
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();
}
Předchozí kód je velmi podobný příkladu POST. Metoda SaveItemAsync volá PutAsync místo PostAsync .
Následující příklad ukazuje požadavek HTTP DELETE:
public async Task DeleteItemAsync(long itemId)
{
using var httpResponse =
await _httpClient.DeleteAsync($"/api/TodoItems/{itemId}");
httpResponse.EnsureSuccessStatusCode();
}
V předchozím kódu volá DeleteItemAsync metoda DeleteAsync . Vzhledem k tomu, že požadavky HTTP DELETE obvykle neobsahují žádné tělo, metoda neposkytuje přetížení, které přijímá DeleteAsync instanci HttpContent .
Další informace o použití různých operací HTTP s HttpClient najdete v tématu HttpClient .
Middleware pro odchozí požadavky
HttpClient má koncept delegování obslužných rutin, které lze propojit pro odchozí požadavky HTTP. IHttpClientFactory:
Zjednodušuje definování obslužných rutin, které se mají použít pro každého pojmenovaného klienta.
Podporuje registraci a řetězení více obslužných rutin pro sestavení kanálu middlewaru pro odchozí požadavky. Každá z těchto obslužných rutin může provádět práci před a po odchozím požadavku. Tento model:
- Podobá se příchozímu middlewaru v ASP.NET Core.
- Poskytuje mechanismus pro správu průřezových problémů ohledně požadavků HTTP, jako jsou například:
- Mezipaměti
- zpracování chyb
- Serializace
- protokolování
Vytvoření delegující obslužné rutiny:
- Odvodit z DelegatingHandler .
- Přepište SendAsync . Před předáním požadavku další obslužné rutině v kanálu spusťte kód:
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);
}
}
Předchozí kód zkontroluje, jestli X-API-KEY je hlavička v požadavku. Pokud X-API-KEY chybí , vrátí se BadRequest .
Do konfigurace pro s je možné přidat více HttpClient obslužných Microsoft.Extensions.DependencyInjection.HttpClientBuilderExtensions.AddHttpMessageHandler rutin:
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.
V předchozím kódu je ValidateHeaderHandler zaregistrovaný u induividovaných ing. Po registraci AddHttpMessageHandler lze volat a předáte typ obslužné rutiny.
Více obslužných rutin lze zaregistrovat v pořadí, v pořadí, ve které by měly být provedeny. Každá obslužná rutina zabalí další obslužnou rutinu do posledního HttpClientHandler provedení požadavku:
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>();
Použití IN v middlewaru odchozích požadavků
Když IHttpClientFactory vytvoří novou delegující obslužnou rutinu, použije dič ke splnění parametrů konstruktoru obslužné rutiny. IHttpClientFactory vytvoří samostatný obor DI pro každou obslužnou rutinu, což může vést k překvapivému chování, když obslužná rutina využívá vymezenou službu.
Představte si například následující rozhraní a jeho implementaci, která představuje úlohu jako operaci s identifikátorem OperationId :
public interface IOperationScoped
{
string OperationId { get; }
}
public class OperationScoped : IOperationScoped
{
public string OperationId { get; } = Guid.NewGuid().ToString()[^4..];
}
Jak jeho název IOperationScoped napovídá, je zaregistrovaný u dividované domény s vymezenou životností:
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();
}
Následující obslužná rutina delegování využívá a používá k IOperationScoped nastavení X-OPERATION-ID hlavičky pro odchozí požadavek:
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);
}
}
V souboru HttpRequestsSample ke stažení] přejděte na /Operation stránku a aktualizujte ji. Hodnota rozsahu požadavku se mění pro každý požadavek, ale hodnota oboru obslužné rutiny se mění jenom každých 5 sekund.
Obslužné rutiny mohou záviset na službách libovolného oboru. Služby, na které obslužné rutiny závisí, jsou uvolněny, když je obslužná rutina odstraněna.
Ke sdílení stavu jednotlivých požadavků s obslužnou rutinou zpráv použijte jeden z následujících přístupů:
- Předejte data obslužné rutině pomocí HttpRequestMessage.Properties.
- Pro IHttpContextAccessor přístup k aktuálnímu požadavku použijte .
- Vytvořte vlastní AsyncLocal<T> objekt úložiště pro předání dat.
Použití obslužných rutin založených na Polly
IHttpClientFactory se integruje s knihovnou třetí strany Polly. Polly je komplexní knihovna odolnosti a zpracování přechodných chyb pro .NET. Umožňuje vývojářům vyjadřovat zásady, jako jsou opakování, jistič, časový limit, izolace přepážek a záložní model, a to plynule a bezpečným způsobem pro přístup z více vláken.
K dispozici jsou metody rozšíření, které umožňují používat zásady Polly s HttpClient nakonfigurovanou instancí. Rozšíření Polly podporují přidávání obslužných rutin založených na Polly do klientů. Polly vyžaduje balíček NuGet Microsoft.Extensions.Http.Polly.
Zpracování přechodných chyb
K chybám obvykle dochází v případě přechodných externích volání HTTP. AddTransientHttpErrorPolicy umožňuje definovat zásady pro zpracování přechodných chyb. Zásady nakonfigurované pro AddTransientHttpErrorPolicy zpracování následujících odpovědí:
- HttpRequestException
- HTTP 5xx
- HTTP 408
AddTransientHttpErrorPolicy poskytuje přístup k objektu PolicyBuilder nakonfigurovanmu pro zpracování chyb představujících možnou přechodnou chybu:
public void ConfigureServices(IServiceCollection services)
{
services.AddHttpClient<UnreliableEndpointCallerService>()
.AddTransientHttpErrorPolicy(p =>
p.WaitAndRetryAsync(3, _ => TimeSpan.FromMilliseconds(600)));
// Remaining code deleted for brevity.
V předchozím kódu je WaitAndRetryAsync definována zásada. Neúspěšné požadavky se mezi pokusy zkusí až třikrát zopakovat se zpožděním 600 ms.
Dynamické výběr zásad
Metody rozšíření jsou k dispozici pro přidání obslužných rutin založených na Polly, například AddPolicyHandler . Následující přetížení AddPolicyHandler požadavek prověří a rozhodne, které zásady se mají použít:
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);
Pokud je v předchozím kódu odchozí požadavek HTTP GET, použije se časový limit 10 sekund. U jakékoli jiné metody HTTP se použije časový limit 30 sekund.
Přidání více obslužných rutin Polly
Zásady Polly se běžně vnořuje:
services.AddHttpClient("multiplepolicies")
.AddTransientHttpErrorPolicy(p => p.RetryAsync(3))
.AddTransientHttpErrorPolicy(
p => p.CircuitBreakerAsync(5, TimeSpan.FromSeconds(30)));
V předchozím příkladu:
- Přidávají se dvě obslužné rutiny.
- První obslužná rutina AddTransientHttpErrorPolicy používá k přidání zásady opakování. Neúspěšné požadavky se zkusí až třikrát.
- Druhé volání
AddTransientHttpErrorPolicypřidá zásadu jističe. Další externí požadavky se zablokují po dobu 30 sekund, pokud se sekvenčně provedlo 5 neúspěšných pokusů. Zásady jističe jsou stavové. Všechna volání prostřednictvím tohoto klienta sdílejí stejný stav okruhu.
Přidání zásad z registru Polly
Přístup ke správě pravidelně používaných zásad je definovat je jednou a zaregistrovat je pomocí PolicyRegistry .
V následujícím kódu:
- Přidávají se "běžné" a "dlouhé" zásady.
- AddPolicyHandlerFromRegistry přidá z registru běžné a dlouhé zásady.
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.
Další informace o IHttpClientFactory integracích a Polly najdete na wikiwebu Polly.
HttpClient a správa doby života
Nová HttpClient instance se vrátí CreateClient pokaždé, když se volá v IHttpClientFactory . Vytvoří HttpMessageHandler se pro pojmenovaného klienta. Továrna spravuje životnost HttpMessageHandler instancí.
IHttpClientFactory fondy HttpMessageHandler instancí vytvořených továrnou, aby se snížila spotřeba prostředků. Instance se může znovu použít z fondu při vytváření nové instance, pokud její životnost HttpMessageHandler HttpClient nevyšla.
Sdružování obslužných rutin je žádoucí, protože každá obslužná rutina obvykle spravuje vlastní základní připojení HTTP. Vytvoření více obslužných rutin, než je potřeba, může vést ke zpoždění připojení. Některé obslužné rutiny také udržují připojení otevřená po neomezenou dobu, což může zabránit tomu, aby obslužná rutina reagovala na změny DNS (Domain Name System).
Výchozí doba života obslužné rutiny je dvě minuty. Výchozí hodnotu je možné přepsat pro jednoho pojmenovaného klienta:
public void ConfigureServices(IServiceCollection services)
{
services.AddHttpClient("extendedhandlerlifetime")
.SetHandlerLifetime(TimeSpan.FromMinutes(5));
// Remaining code deleted for brevity.
HttpClient Instance lze obecně považovat za objekty .NET, které nevyžadují vyřazení. Vyřazení zruší odchozí požadavky a zaručuje, že danou instanci nelze HttpClient po volání Dispose použít. IHttpClientFactory sleduje a odstraňuje prostředky používané HttpClient instancemi.
Udržování jedné HttpClient instance v živém platnosti po dlouhou dobu je běžným vzorem, který se používá před iniciací IHttpClientFactory . Po migraci na se tento model stane nepotřebným. IHttpClientFactory
Alternativy k IHttpClientFactory
Použití IHttpClientFactory v aplikaci s podporou diody zabrání:
- Problémy s vyčerpáváním prostředků sdružování
HttpMessageHandlerinstancí - Zastaralé problémy s DNS instancemi v
HttpMessageHandlerpravidelných intervalech
Existují alternativní způsoby, jak vyřešit předchozí problémy s využitím dlouhodobé SocketsHttpHandler instance.
- Vytvořte instanci
SocketsHttpHandlerpři spuštění aplikace a použijte ji po dobu životnosti aplikace. - Nakonfigurujte PooledConnectionLifetime na odpovídající hodnotu na základě časů aktualizace DNS.
- Podle
HttpClientpotřeby vytvořte instance pomocí příkazunew HttpClient(handler, disposeHandler: false).
Předchozí přístupy řeší problémy správy prostředků, které IHttpClientFactory řeší podobným způsobem.
- Sdílí
SocketsHttpHandlerpřipojení meziHttpClientinstancemi. Toto sdílení zabraňuje vyčerpání soketů. SocketsHttpHandlerCykluje připojení podle , aby se zabrániloPooledConnectionLifetimeproblémům se zastaralou službou DNS.
CookieS
Instance ve fondu HttpMessageHandler mají za výsledek sdílení CookieContainer objektů. Neočekávané sdílení CookieContainer objektů často vede k nesprávnému kódu. U aplikací, které cookie vyžadují , zvažte následující:
- Zakázání automatického cookie zpracování
- Vyhnout
IHttpClientFactory
Volání ConfigurePrimaryHttpMessageHandler pro zákaz automatického cookie zpracování:
services.AddHttpClient("configured-disable-automatic-cookies")
.ConfigurePrimaryHttpMessageHandler(() =>
{
return new HttpClientHandler()
{
UseCookies = false,
};
});
protokolování
Klienti vytvoření IHttpClientFactory prostřednictvím zpráv protokolu záznamů pro všechny požadavky. Povolte v konfiguraci protokolování odpovídající úroveň informací, abyste viděli výchozí zprávy protokolu. Další protokolování, například protokolování hlaviček požadavků, je zahrnuto pouze na úrovni trasování.
Kategorie protokolu použitá pro každého klienta obsahuje název klienta. Klient s názvem MyNamedClient například protokoluje zprávy s kategorií System.Net.Http.HttpClient. MyNamedClient. LogicalHandler. Zprávy s příponou LogicalHandler se vyskytují mimo kanál obslužné rutiny požadavku. V požadavku jsou zprávy protokolovány dříve, než je zpracují jakékoli jiné obslužné rutiny v kanálu. V odpovědi se zprávy protokolují poté, co odpověď obdrží jakákoli jiná obslužná rutina kanálu.
K protokolování dochází také v kanálu obslužné rutiny požadavku. V příkladu MyNamedClient jsou tyto zprávy protokolovány s kategorií protokolu System.Net.Http.HttpClient. MyNamedClient. ClientHandler". K tomuto požadavku dochází po spuštění všech ostatních obslužných rutin a bezprostředně před odesláním požadavku. V odpovědi toto protokolování zahrnuje stav odpovědi před tím, než předá zpět kanál obslužné rutiny.
Povolení protokolování mimo kanál a uvnitř kanálu umožňuje kontrolu změn ostatních obslužných rutin kanálu. To může zahrnovat změny hlaviček požadavků nebo stavového kódu odpovědi.
Zahrnutí názvu klienta do kategorie protokolu umožňuje filtrování protokolů pro konkrétní pojmenované klienty.
Konfigurace HttpMessageHandler
Může být nutné řídit konfiguraci vnitřních HttpMessageHandler součástí používaných klientem.
Při IHttpClientBuilder přidávání pojmenovaných nebo typovaných klientů se vrátí . Rozšiřující ConfigurePrimaryHttpMessageHandler metodu lze použít k definování delegáta. Delegát slouží k vytvoření a konfiguraci primárního HttpMessageHandler používaného tímto klientem:
public void ConfigureServices(IServiceCollection services)
{
services.AddHttpClient("configured-inner-handler")
.ConfigurePrimaryHttpMessageHandler(() =>
{
return new HttpClientHandler()
{
AllowAutoRedirect = false,
UseDefaultCredentials = true
};
});
// Remaining code deleted for brevity.
Použití IHttpClientFactory v aplikaci konzoly
V aplikaci konzoly přidejte do projektu následující odkazy na balíček:
V následujícím příkladu:
- IHttpClientFactory je zaregistrovaný v kontejneru služby obecného hostitele.
MyServicevytvoří ze služby instanci klientské továrny, která se používá k vytvořeníHttpClientobjektu .HttpClientse používá k načtení webové stránky.Mainvytvoří obor, který spustí metodu služby a zapíše prvních 500 znaků obsahu webovéGetPagestránky do konzoly.
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}";
}
}
}
}
Middleware pro šíření hlaviček
Šíření hlaviček je ASP.NET Core, který šíří hlavičky PROTOKOLU HTTP z příchozího požadavku na odchozí požadavky klienta HTTP. Použití šíření hlaviček:
Odkašlete na balíček Microsoft.AspNetCore.HeaderPropagation.
Nakonfigurujte middleware a v
HttpClientsouboruStartup: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(); }); }Klient obsahuje nakonfigurované hlavičky pro odchozí požadavky:
var client = clientFactory.CreateClient("MyForwardingClient"); var response = client.GetAsync(...);
Další zdroje informací
Od Gordona Užkina, Steve Gordona, Thena Condronaa Ryana Nowaka.
Objekt IHttpClientFactory je možné zaregistrovat a použít ke konfiguraci HttpClient a vytváření instancí v aplikaci. IHttpClientFactory nabízí následující výhody:
- Poskytuje centrální umístění pro pojmenování a konfiguraci
HttpClientlogických instancí. Například klient s názvem github může být zaregistrovaný a nakonfigurovaný pro přístup k GitHub. Pro obecný přístup je možné zaregistrovat výchozího klienta. - Kodifikuje koncept odchozího middlewaru delegování obslužných rutin v
HttpClient. Poskytuje rozšíření middlewaru založeného na Polly, která využívají delegování obslužných rutin vHttpClientnástroji . - Spravuje sdružování a životnost základních
HttpClientMessageHandlerinstancí. Automatická správa zabraňuje běžným problémům se systémem DNS (Domain Name System), ke kterým dochází při ruční správěHttpClientživotnosti. - Přidá konfigurovatelné prostředí protokolování (prostřednictvím ) pro všechny požadavky odeslané
ILoggerprostřednictvím klientů vytvořených továrnou.
Zobrazení nebo stažení ukázkového kódu (stažení).
Vzorový kód v této verzi tématu používá System.Text.Json k deserializaci obsahu JSON vráceného v odpovědích HTTP. Pro ukázky, které používají a , použijte selektor verzí k výběru verze Json.NET ReadAsAsync<T> 2.x tohoto tématu.
Spotřeby
V aplikaci IHttpClientFactory je možné použít několik způsobů:
Nejlepší přístup závisí na požadavcích aplikace.
Základní použití
IHttpClientFactory je možné zaregistrovat voláním 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.
O IHttpClientFactory objekt je možné požádat pomocí injektáže závislostí (DI). Následující kód používá IHttpClientFactory k vytvoření HttpClient instance :
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>();
}
}
}
Použití IHttpClientFactory příkazu like v předchozím příkladu je dobrým způsobem, jak refaktorovat existující aplikaci. Nemá žádný vliv na způsob HttpClient použití. Na místech, kde jsou instance vytvořené v existující aplikaci, nahraďte tyto HttpClient výskyty voláním CreateClient .
Pojmenovaní klienti
Pojmenovaní klienti jsou dobrou volbou v případě, že:
- Aplikace vyžaduje mnoho různých použití
HttpClient. - Mnoho
HttpClientz nich má jinou konfiguraci.
Konfiguraci pojmenovaného HttpClient objektu je možné zadat během registrace v Startup.ConfigureServices nástroji :
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");
});
V předchozím kódu je klient nakonfigurovaný s:
- Základní adresa
https://api.github.com/. - Dvě hlavičky vyžadované pro práci s rozhraním GITHUB API.
CreateClient
Pokaždé CreateClient se volá:
- Vytvoří se nová
HttpClientinstance . - Volá se konfigurační akce.
Pokud chcete vytvořit pojmenovaného klienta, předejte jeho název do 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>();
}
}
}
V předchozím kódu nemusí požadavek zadat název hostitele. Kód může předat pouze cestu, protože se používá základní adresa nakonfigurovaná pro klienta.
Typové klienti
Klienti typu:
- Poskytněte stejné funkce jako pojmenované klienty, aniž by bylo nutné používat řetězce jako klíče.
- Poskytuje IntelliSense a pomocníka s kompilátorem při spotřebovávání klientů.
- Zadejte jedno umístění, které chcete nakonfigurovat, a pracujte s ním
HttpClient. Můžete například použít jednoho typu klienta:- Pro jeden koncový bod back-endu.
- Zapouzdřit veškerou práci s koncovým bodem.
- Práce s DI a může být vložena tam, kde je to potřeba v aplikaci.
Typový klient přijímá HttpClient parametr ve svém konstruktoru:
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");
}
}
V předchozím kódu:
- Konfigurace je přesunuta do typovaného klienta.
HttpClientObjekt je vystaven jako veřejná vlastnost.
Je možné vytvořit metody specifické pro rozhraní API, které zpřístupňují HttpClient funkce. Například GetAspNetDocsIssues Metoda zapouzdřuje kód pro načtení otevřených problémů.
Následující kód volá AddHttpClient v Startup.ConfigureServices k registraci typové třídy klienta:
services.AddHttpClient<GitHubService>();
Typový klient je zaregistrován jako přechodný s DI. V předchozím kódu se AddHttpClient registruje GitHubService jako dočasná služba. Tato registrace používá metodu továrny k těmto účelům:
- Vytvořte instanci
HttpClient. - Vytvořte instanci objektu s
GitHubServicepředáním v instanciHttpClientdo jeho konstruktoru.
Typového klienta lze vložit a spotřebovat přímo:
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>();
}
}
}
Konfiguraci pro typového klienta lze zadat během registrace v nástroji Startup.ConfigureServices , nikoli v konstruktoru typovaného klienta:
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");
});
HttpClientMůže být zapouzdřen v rámci typovaného klienta. Místo toho, abyste ho vystavili jako vlastnost, definujte metodu, která volá HttpClient interně instanci:
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);
}
}
V předchozím kódu HttpClient je uložen v soukromém poli. Přístup k aplikaci HttpClient je veřejný GetRepos metodou.
Vygenerované klienty
IHttpClientFactory dá se použít v kombinaci s knihovnami třetích stran, jako je REFIT. REFIT je knihovna REST pro .NET. Převede rozhraní REST API na živá rozhraní. Implementace rozhraní je vygenerována dynamicky pomocí RestService , a používá HttpClient se k vytvoření externích volání http.
Rozhraní a odpověď jsou definované tak, aby představovaly externí rozhraní API a jeho odpověď:
public interface IHelloClient
{
[Get("/helloworld")]
Task<Reply> GetMessageAsync();
}
public class Reply
{
public string Message { get; set; }
}
K vygenerování implementace se dá přidat typový klient s použitím REFIT:
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();
}
Definované rozhraní lze v případě potřeby spotřebovat pomocí implementace, kterou poskytuje DI a REFIT:
[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();
}
}
Vytváření požadavků POST, PUT a DELETE
V předchozích příkladech všechny požadavky HTTP používají příkaz GET HTTP. HttpClient podporuje také jiné příkazy HTTP, včetně:
- POST
- PUT
- DELETE
- POUŽITA
Úplný seznam podporovaných příkazů HTTP naleznete v tématu HttpMethod .
Následující příklad ukazuje, jak vytvořit požadavek HTTP POST:
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();
}
V předchozím kódu CreateItemAsync metoda:
- Zaserializace
TodoItemparametr do formátu JSON pomocíSystem.Text.Json. Tato operace používá instanci JsonSerializerOptions ke konfiguraci procesu serializace. - Vytvoří instanci StringContent pro zabalení serializovaného JSON pro odeslání v těle požadavku HTTP.
- Volání PostAsync pro odeslání obsahu JSON na zadanou adresu URL. Toto je relativní adresa URL, která se přidá do HttpClient. BaseAddress.
- Volání EnsureSuccessStatusCode vyvolávající výjimku, pokud kód stavu odpovědi neindikuje úspěch.
HttpClient podporuje také další typy obsahu. Příklad: MultipartContent a StreamContent. Úplný seznam podporovaného obsahu najdete v tématu HttpContent .
Následující příklad ukazuje požadavek HTTP PUT:
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();
}
Předchozí kód je velmi podobný jako příklad příspěvku. SaveItemAsyncMetoda volá PutAsync místo PostAsync .
Následující příklad ukazuje požadavek HTTP DELETE:
public async Task DeleteItemAsync(long itemId)
{
using var httpResponse =
await _httpClient.DeleteAsync($"/api/TodoItems/{itemId}");
httpResponse.EnsureSuccessStatusCode();
}
V předchozím kódu DeleteItemAsync metoda volá metodu DeleteAsync . Vzhledem k tomu, že žádosti o odstranění HTTP obvykle neobsahují žádné tělo, DeleteAsync Metoda neposkytne přetížení, které přijímá instanci HttpContent .
Další informace o používání různých příkazů HTTP s najdete HttpClient v tématu HttpClient .
Middleware odchozího požadavku
HttpClient má koncepci delegování obslužných rutin, které mohou být propojeny pro odchozí požadavky HTTP. IHttpClientFactory:
Zjednodušuje definování obslužných rutin, které se mají použít pro každého pojmenovaného klienta.
Podporuje registraci a řetězení více obslužných rutin pro sestavení kanálu middleware odchozího požadavku. Každý z těchto obslužných rutin je schopný provést práci před odchozím požadavkem a po ní. Tento model:
- Se podobá příchozímu kanálu middleware v ASP.NET Core.
- Poskytuje mechanismus pro správu otázek mezi jednotlivými požadavky HTTP, jako je například:
- vyrovnávací
- zpracování chyb
- serializace
- protokolování
Vytvoření obslužné rutiny delegování:
- Odvodit z DelegatingHandler .
- Přepsat SendAsync . Před předáním požadavku další obslužné rutině v kanálu spusťte kód:
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);
}
}
Předchozí kód zkontroluje, zda X-API-KEY je hlavička v žádosti. Pokud X-API-KEY chybí, BadRequest je vrácena.
Do konfigurace pro se dá přidat víc než jedna obslužná rutina 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.
V předchozím kódu ValidateHeaderHandler je zaregistrována v di. Po registraci je AddHttpMessageHandler možné ji volat s předáním typu pro obslužnou rutinu.
Více obslužných rutin lze registrovat v pořadí, ve kterém by měly být spuštěny. Každá obslužná rutina zabalí další obslužnou rutinu, dokud poslední HttpClientHandler nespustí požadavek:
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>();
V datamiddlewari odchozích požadavků použijte DI.
Při IHttpClientFactory Vytvoření nové obslužné rutiny delegování používá parametr di ke splnění parametrů konstruktoru obslužné rutiny. IHttpClientFactory vytvoří samostatný obor di pro každou obslužnou rutinu, což může vést k překvapivé chování, když obslužná rutina spotřebovává vymezenou službu.
Zvažte například následující rozhraní a jeho implementaci, která představuje úkol jako operaci s identifikátorem OperationId :
public interface IOperationScoped
{
string OperationId { get; }
}
public class OperationScoped : IOperationScoped
{
public string OperationId { get; } = Guid.NewGuid().ToString()[^4..];
}
Jak je navrženo, IOperationScoped je registrováno s di pomocí oboru platnosti:
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();
}
Následující delegování obslužné rutiny využívá a používá IOperationScoped k nastavení X-OPERATION-ID záhlaví odchozího požadavku:
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);
}
}
V části HttpRequestsSample Stáhnout] přejděte na /Operation stránku a aktualizujte ji. Hodnota rozsahu požadavku se pro každý požadavek změní, ale hodnota oboru obslužné rutiny se mění jenom každých 5 sekund.
Obslužné rutiny mohou záviset na službách jakéhokoli oboru. Služby, na kterých obslužné rutiny závisejí, jsou uvolněny při uvolnění obslužné rutiny.
Ke sdílení stavu jednotlivých požadavků pomocí obslužných rutin zpráv použijte jeden z následujících přístupů:
- Předejte data do obslužné rutiny pomocí zprávy HttpRequestMessage. Properties.
- IHttpContextAccessorPro přístup k aktuálnímu požadavku použijte.
- Vytvořte vlastní AsyncLocal<T> objekt úložiště, který bude předávat data.
Použití obslužných rutin založené na Polly
IHttpClientFactory integruje se s knihovnou Pollytřetí strany. Polly je komplexní odolnost a přechodná knihovna pro zpracování chyb pro .NET. Umožňuje vývojářům vyjádřit zásady, jako je opakování, přerušení okruhů, časový limit, izolaci přepážek a nouzové řešení v rámci Fluent a bezpečného přístupu z více vláken.
K dispozici jsou rozšiřující metody umožňující použití zásad Polly s konfigurovanými HttpClient instancemi. Rozšíření Polly podporují přidávání obslužných rutin založených na Polly do klientů. Polly vyžaduje balíček Microsoft. extensions. Http. Polly NuGet.
Zpracování přechodných chyb
K chybám obvykle dochází, když jsou externí volání HTTP přechodný. AddTransientHttpErrorPolicy umožňuje definovat zásadu pro zpracování přechodných chyb. Zásady nakonfigurované s nástrojem AddTransientHttpErrorPolicy zpracovávají následující odpovědi:
- HttpRequestException
- HTTP 5xx
- HTTP 408
AddTransientHttpErrorPolicy poskytuje přístup k PolicyBuilder objektu nakonfigurovanému pro zpracování chyb představujících možnou přechodnou chybu:
public void ConfigureServices(IServiceCollection services)
{
services.AddHttpClient<UnreliableEndpointCallerService>()
.AddTransientHttpErrorPolicy(p =>
p.WaitAndRetryAsync(3, _ => TimeSpan.FromMilliseconds(600)));
// Remaining code deleted for brevity.
V předchozím kódu WaitAndRetryAsync je definována zásada. U neúspěšných žádostí se Opakovaný pokus opakuje více než třikrát s prodlevou 600 MS mezi pokusy.
Dynamické výběry zásad
Rozšiřující metody jsou k dispozici pro přidání obslužných rutin na základě Polly, například AddPolicyHandler . Následující AddPolicyHandler přetížení zkontroluje požadavek na rozhodnutí, které zásady se mají použít:
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);
Pokud je v předchozím kódu odchozí požadavek HTTP GET, použije se časový limit 10 sekund. Pro jakoukoliv jinou metodu HTTP se použije časový limit 30 sekund.
Přidání více obslužných rutin Polly
Je běžné vnořovat zásady Polly:
services.AddHttpClient("multiplepolicies")
.AddTransientHttpErrorPolicy(p => p.RetryAsync(3))
.AddTransientHttpErrorPolicy(
p => p.CircuitBreakerAsync(5, TimeSpan.FromSeconds(30)));
V předchozím příkladu:
- Přidávají se dvě obslužné rutiny.
- První obslužná rutina používá AddTransientHttpErrorPolicy k přidání zásady opakování. Neúspěšné požadavky se opakují třikrát.
- Druhé
AddTransientHttpErrorPolicyvolání přidá zásadu pro přerušení okruhu. Další externí požadavky se zablokují po dobu 30 sekund, pokud se 5 nezdařených pokusů vyskytnou sekvenčně. Zásady pro dělení na okruhy jsou stavové. Všechna volání prostřednictvím tohoto klienta sdílejí stejný stav okruhu.
Přidání zásad z registru Polly
Přístup ke správě často používaných zásad je definovat jednou a zaregistrovat je pomocí PolicyRegistry .
V následujícím kódu:
- Přidají se zásady "regular" a "Long".
- AddPolicyHandlerFromRegistry Přidá do registru zásady "regular" a "Long".
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.
Další informace o IHttpClientFactory Polly integrech a integraci najdete na wikiwebu Polly.
Správa HttpClient a životního cyklu
Nová HttpClient instance se vrátí pokaždé, když CreateClient se zavolá na IHttpClientFactory . HttpMessageHandlerVytvoří se pro jednotlivé pojmenované klienty. Továrna spravuje životnost HttpMessageHandler instancí.
IHttpClientFactory Vytvoří fondy HttpMessageHandler instancí vytvořených výrobou, aby se snížila spotřeba prostředků. Instance se dá HttpMessageHandler znovu použít z fondu při vytváření nové HttpClient instance, pokud její doba platnosti ještě nevypršela.
Sdružování obslužných rutin je žádoucí, protože každá obslužná rutina obvykle spravuje vlastní podkladová připojení HTTP. Vytváření dalších obslužných rutin, než je potřeba, může způsobit zpoždění připojení. Některé obslužné rutiny také udržují připojení otevřené po neomezenou dobu, což může zabránit obslužné rutině v reakce na změny DNS (Domain Name System).
Výchozí životnost obslužné rutiny je dvě minuty. Výchozí hodnota může být přepsána podle pojmenovaných klientů:
public void ConfigureServices(IServiceCollection services)
{
services.AddHttpClient("extendedhandlerlifetime")
.SetHandlerLifetime(TimeSpan.FromMinutes(5));
// Remaining code deleted for brevity.
HttpClient instance je obecně možné považovat za objekty .NET, které nevyžadují vyřazení. Vyřazení zruší odchozí žádosti a zaručuje, že danou HttpClient instanci nelze použít po volání Dispose . IHttpClientFactory sleduje a odstraňuje prostředky používané HttpClient instancemi.
Udržování jediné HttpClient instance po dlouhou dobu je společný vzor, který se používá před zahájením IHttpClientFactory . Tento model se po migraci na nedá zbytečné IHttpClientFactory .
Alternativy k IHttpClientFactory
Použití IHttpClientFactory v aplikaci s podporou di se vyhne:
- Problémy s vyčerpáním prostředků díky sdružování
HttpMessageHandlerinstancí. - Zastaralé problémy se službou DNS cyklicky cyklických
HttpMessageHandlerinstancí v pravidelných intervalech.
Existují alternativní způsoby, jak vyřešit předchozí problémy pomocí dlouhotrvající SocketsHttpHandler instance.
- Vytvořte instanci aplikace,
SocketsHttpHandlerkdyž se aplikace spustí a použije se po celou dobu životnosti aplikace. - Proveďte konfiguraci PooledConnectionLifetime na odpovídající hodnotu na základě časů aktualizace DNS.
- Vytvořte
HttpClientinstancenew HttpClient(handler, disposeHandler: false)podle potřeby.
Předchozí přístupy vyřeší problémy se správou prostředků, které se IHttpClientFactory podobným způsobem vyřeší.
SocketsHttpHandlerSdílí připojení meziHttpClientinstancemi. Toto sdílení zabraňuje vyčerpání soketů.SocketsHttpHandlerCyklická připojení jsou na základě toho,PooledConnectionLifetimeaby se předešlo zastaralým problémům s DNS.
Cookiepracují
Instance ve fondu mají HttpMessageHandler za následek CookieContainer Sdílení objektů. Neočekávané CookieContainer Sdílení objektů často vede k nesprávnému kódu. U aplikací, které vyžadují cookie s, zvažte jednu z těchto akcí:
- Zákaz automatického cookie zpracování
- Opakované
IHttpClientFactory
Volání ConfigurePrimaryHttpMessageHandler pro zakázání automatického cookie zpracování:
services.AddHttpClient("configured-disable-automatic-cookies")
.ConfigurePrimaryHttpMessageHandler(() =>
{
return new HttpClientHandler()
{
UseCookies = false,
};
});
protokolování
Klienti vytvoření prostřednictvím IHttpClientFactory záznamu zprávy protokolu pro všechny požadavky. V konfiguraci protokolování povolte příslušnou úroveň informací, aby se zobrazily výchozí zprávy protokolu. Další protokolování, jako je protokolování hlaviček požadavků, je zahrnuté jenom na úrovni trasování.
Kategorie protokolu použitá pro každého klienta zahrnuje název klienta. Klient s názvem MyNamedClient například protokoluje zprávy s kategorií "System .NET. http. HttpClient. MyNamedClient. LogicalHandler". Zprávy s příponou LogicalHandler se vyskytují mimo kanál obslužné rutiny žádosti. V žádosti se zprávy protokolují předtím, než je zpracuje kterákoli jiný obslužná rutina v kanálu. Na základě odpovědi se zprávy zaprotokolují, až ostatní obslužné rutiny kanálu obdrží odpověď.
K protokolování dojde také uvnitř kanálu obslužné rutiny žádosti. V příkladu MyNamedClient jsou tyto zprávy protokolovány pomocí kategorie log "System .NET. http. HttpClient. MyNamedClient. ClientHandler". Pro požadavek se k tomu dochází po spuštění všech ostatních obslužných rutin a bezprostředně před odesláním žádosti. V odpovědi Toto protokolování zahrnuje stav odpovědi předtím, než se přepošle zpět přes kanál obslužné rutiny.
Povolení protokolování mimo kanál a uvnitř kanálu umožňuje kontrolu změn provedených ostatními obslužnými rutinami kanálu. To může zahrnovat změny hlaviček žádostí nebo kód stavu odpovědi.
Zahrnutí názvu klienta do kategorie protokolu umožňuje filtrování protokolu pro konkrétní pojmenované klienty.
Konfigurace HttpMessageHandler
Může být nutné řídit konfiguraci vnitřního HttpMessageHandler používaného klienta.
IHttpClientBuilderPři přidávání pojmenovaných nebo typových klientů se vrátí. ConfigurePrimaryHttpMessageHandlerMetodu rozšíření lze použít k definování delegáta. Delegát slouží k vytvoření a konfiguraci primárního HttpMessageHandler používaného klienta:
public void ConfigureServices(IServiceCollection services)
{
services.AddHttpClient("configured-inner-handler")
.ConfigurePrimaryHttpMessageHandler(() =>
{
return new HttpClientHandler()
{
AllowAutoRedirect = false,
UseDefaultCredentials = true
};
});
// Remaining code deleted for brevity.
Použití IHttpClientFactory v konzolové aplikaci
V aplikaci konzoly přidejte do projektu následující odkazy na balíček:
V následujícím příkladu:
- IHttpClientFactory je zaregistrován v kontejneru služby obecného hostitele .
MyServiceVytvoří instanci klientské továrny ze služby, která se používá k vytvořeníHttpClient.HttpClientslouží k načtení webové stránky.Mainvytvoří obor pro provedeníGetPagemetody služby a zapíše první 500 znaků obsahu webové stránky do konzoly.
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}";
}
}
}
}
Middleware pro šíření hlaviček
Šíření hlaviček je ASP.NET Core, který šíří hlavičky PROTOKOLU HTTP z příchozího požadavku na odchozí požadavky klienta HTTP. Použití šíření hlaviček:
Odkašlete na balíček Microsoft.AspNetCore.HeaderPropagation.
Nakonfigurujte middleware a v
HttpClientsouboruStartup: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(); }); }Klient obsahuje nakonfigurované hlavičky pro odchozí požadavky:
var client = clientFactory.CreateClient("MyForwardingClient"); var response = client.GetAsync(...);
Další zdroje informací
Od Gordona Užkina, Steve Gordona, Thena Condronaa Ryana Nowaka.
Objekt IHttpClientFactory je možné zaregistrovat a použít ke konfiguraci HttpClient a vytváření instancí v aplikaci. IHttpClientFactory nabízí následující výhody:
- Poskytuje centrální umístění pro pojmenování a konfiguraci
HttpClientlogických instancí. Například klient s názvem github může být zaregistrovaný a nakonfigurovaný pro přístup k GitHub. Pro obecný přístup je možné zaregistrovat výchozího klienta. - Kodifikuje koncept odchozího middlewaru delegování obslužných rutin v
HttpClient. Poskytuje rozšíření middlewaru založeného na Polly, která využívají delegování obslužných rutin vHttpClientnástroji . - Spravuje sdružování a životnost základních
HttpClientMessageHandlerinstancí. Automatická správa zabraňuje běžným problémům se systémem DNS (Domain Name System), ke kterým dochází při ruční správěHttpClientživotnosti. - Přidá konfigurovatelné prostředí protokolování (prostřednictvím ) pro všechny požadavky odeslané
ILoggerprostřednictvím klientů vytvořených továrnou.
Zobrazení nebo stažení ukázkového kódu (stažení).
Vzorový kód v této verzi tématu používá System.Text.Json k deserializaci obsahu JSON vráceného v odpovědích HTTP. Pro ukázky, které používají a , použijte selektor verzí k výběru verze Json.NET ReadAsAsync<T> 2.x tohoto tématu.
Spotřeby
V aplikaci IHttpClientFactory je možné použít několik způsobů:
Nejlepší přístup závisí na požadavcích aplikace.
Základní použití
IHttpClientFactory je možné zaregistrovat voláním 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.
O IHttpClientFactory objekt je možné požádat pomocí injektáže závislostí (DI). Následující kód používá IHttpClientFactory k vytvoření HttpClient instance :
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>();
}
}
}
Použití IHttpClientFactory příkazu like v předchozím příkladu je dobrým způsobem, jak refaktorovat existující aplikaci. Nemá žádný vliv na způsob HttpClient použití. Na místech, kde jsou instance vytvořené v existující aplikaci, nahraďte tyto HttpClient výskyty voláním CreateClient .
Pojmenovaní klienti
Pojmenovaní klienti jsou dobrou volbou v případě, že:
- Aplikace vyžaduje mnoho různých použití
HttpClient. - Mnoho
HttpClientz nich má jinou konfiguraci.
Konfiguraci pojmenovaného HttpClient objektu je možné zadat během registrace v Startup.ConfigureServices nástroji :
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");
});
V předchozím kódu je klient nakonfigurovaný s:
- Základní adresa
https://api.github.com/. - Dvě hlavičky potřebné pro práci s rozhraním GITHUB API.
CreateClient
Pokaždé CreateClient se volá:
- Vytvoří se nová
HttpClientinstance . - Volá se konfigurační akce.
Pokud chcete vytvořit pojmenovaného klienta, předejte jeho název do 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>();
}
}
}
V předchozím kódu nemusí požadavek zadat název hostitele. Kód může předat pouze cestu, protože se používá základní adresa nakonfigurovaná pro klienta.
Typové klienty
Typové klienty:
- Poskytovat stejné funkce jako pojmenovaní klienti bez nutnosti používat řetězce jako klíče.
- Poskytuje IntelliSense a nápovědu kompilátoru při používání klientů.
- Zadejte jedno umístění pro konfiguraci a interakci s konkrétním
HttpClient. Může se například použít jeden typovaný klient:- Pro jeden koncový bod back-endu.
- Zapouzdření veškeré logiky, která se zabývá koncovým bodem.
- Pracujte s injekvencí injekvencí, kde je to v aplikaci potřeba.
Typový klient přijímá parametr HttpClient ve svém konstruktoru:
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);
}
}
Pokud chcete zobrazit komentáře ke kódu přeložené do jiných jazyků než angličtiny, dejte nám vědět v tomto problému diskuze na GitHubu.
V předchozím kódu:
- Konfigurace se přesune do typu klienta.
- Objekt
HttpClientje zpřístupněn jako veřejná vlastnost.
Je možné vytvořit metody specifické pro rozhraní API, které zpřístupňuje HttpClient funkce. Například metoda GetAspNetDocsIssues zapouzdřuje kód pro načtení otevřených problémů.
Následující kód volá AddHttpClient v Startup.ConfigureServices pro registraci typové třídy klienta:
services.AddHttpClient<GitHubService>();
Typový klient je zaregistrovaný jako přechodný u diody. V předchozím kódu se AddHttpClient zaregistruje GitHubService jako přechodná služba. Tato registrace používá metodu továrny k:
- Vytvořte instanci
HttpClient. - Vytvořte instanci
GitHubService, která instanci předáHttpClientsvému konstruktoru.
Typovaného klienta je možné vloženého a spotřebovávat přímo:
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>();
}
}
}
Konfiguraci pro zadaného klienta je možné zadat během registrace v , a ne v Startup.ConfigureServices konstruktoru zadaného klienta:
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");
});
Může HttpClient být zapouzdřen v rámci typové klienta. Místo toho, aby se vystavoval jako vlastnost, definujte metodu, která HttpClient interně volá instanci:
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);
}
}
V předchozím kódu je HttpClient objekt uložen v soukromém poli. Přístup k HttpClient je pomocí veřejné GetRepos metody.
Vygenerovaní klienti
IHttpClientFactoryje možné použít v kombinaci s knihovnami třetích stran, jako je například Refit (Přizpůsobit). Refit je knihovna REST pro .NET. Převádí rozhraní REST API na živá rozhraní. Implementace rozhraní je generována dynamicky pomocí RestService , k provedení externích volání HttpClient HTTP.
Rozhraní a odpověď jsou definovány tak, aby představovaly externí rozhraní API a jeho odpověď:
public interface IHelloClient
{
[Get("/helloworld")]
Task<Reply> GetMessageAsync();
}
public class Reply
{
public string Message { get; set; }
}
Typovaný klient je možné přidat pomocí příkazu Refit pro vygenerování implementace:
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();
}
Definované rozhraní je možné v případě potřeby využívat s implementací, kterou poskytuje DI a Refit:
[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();
}
}
Požadavky POST, PUT a DELETE
V předchozích příkladech používají všechny požadavky HTTP příkaz GET HTTP. HttpClient podporuje také další příkazy HTTP, včetně následujících:
- POST
- PUT
- DELETE
- OPRAVA
Úplný seznam podporovaných operací HTTP najdete v tématu HttpMethod .
Následující příklad ukazuje, jak vytvořit požadavek HTTP POST:
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();
}
V předchozím kódu metoda CreateItemAsync :
- Serializuje parametr
TodoItemdo formátu JSON pomocíSystem.Text.Json. To používá instanci JsonSerializerOptions ke konfiguraci procesu serializace. - Vytvoří instanci pro StringContent zabalení serializovaného formátu JSON pro odeslání v textu požadavku HTTP.
- Zavolá PostAsync metodu , která odešle obsah JSON na zadanou adresu URL. Toto je relativní adresa URL, která se přidá do HttpClient.BaseAddress.
- Zavolá EnsureSuccessStatusCode metodu , která vyvolá výjimku, pokud stavový kód odpovědi neznačí úspěch.
HttpClient podporuje také další typy obsahu. Příklad: MultipartContent a StreamContent. Úplný seznam podporovaných obsahu najdete v tématu HttpContent .
Následující příklad ukazuje požadavek HTTP PUT:
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();
}
Předchozí kód je velmi podobný příkladu POST. Metoda SaveItemAsync volá PutAsync místo PostAsync .
Následující příklad ukazuje požadavek HTTP DELETE:
public async Task DeleteItemAsync(long itemId)
{
using var httpResponse =
await _httpClient.DeleteAsync($"/api/TodoItems/{itemId}");
httpResponse.EnsureSuccessStatusCode();
}
V předchozím kódu volá DeleteItemAsync metoda DeleteAsync . Vzhledem k tomu, že požadavky HTTP DELETE obvykle neobsahují žádné tělo, metoda neposkytuje přetížení, DeleteAsync které přijímá instanci HttpContent .
Další informace o použití různých operací HTTP s HttpClient najdete v tématu HttpClient .
Middleware pro odchozí požadavky
HttpClient má koncept delegování obslužných rutin, které lze propojit pro odchozí požadavky HTTP. IHttpClientFactory:
Zjednodušuje definování obslužných rutin, které se mají použít pro každého pojmenovaného klienta.
Podporuje registraci a řetězení více obslužných rutin pro sestavení kanálu middlewaru pro odchozí požadavky. Každá z těchto obslužných rutin může provádět práci před a po odchozím požadavku. Tento model:
- Podobá se příchozímu middlewaru v ASP.NET Core.
- Poskytuje mechanismus pro správu průřezových problémů ohledně požadavků HTTP, jako jsou například:
- Mezipaměti
- zpracování chyb
- Serializace
- protokolování
Vytvoření delegující obslužné rutiny:
- Odvodit z DelegatingHandler .
- Přepište SendAsync . Před předáním požadavku další obslužné rutině v kanálu spusťte kód:
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);
}
}
Předchozí kód zkontroluje, jestli X-API-KEY je hlavička v požadavku. Pokud X-API-KEY chybí , vrátí se BadRequest .
Do konfigurace pro s je možné přidat více než HttpClient jednu obslužnou rutinu: 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.
V předchozím kódu je ValidateHeaderHandler zaregistrovaný u induividovaných ing. Po registraci AddHttpMessageHandler lze volat a předáte typ obslužné rutiny.
Více obslužných rutin lze zaregistrovat v pořadí, v pořadí, ve které by měly být provedeny. Každá obslužná rutina zabalí další obslužnou rutinu do posledního HttpClientHandler provedení požadavku:
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>();
Použití IN v middlewaru odchozích požadavků
Když IHttpClientFactory vytvoří novou delegující obslužnou rutinu, použije dič ke splnění parametrů konstruktoru obslužné rutiny. IHttpClientFactory vytvoří samostatný obor DI pro každou obslužnou rutinu, což může vést k překvapivému chování, když obslužná rutina využívá vymezenou službu.
Představte si například následující rozhraní a jeho implementaci, která představuje úlohu jako operaci s identifikátorem OperationId :
public interface IOperationScoped
{
string OperationId { get; }
}
public class OperationScoped : IOperationScoped
{
public string OperationId { get; } = Guid.NewGuid().ToString()[^4..];
}
Jak jeho název IOperationScoped napovídá, je zaregistrován u di di s použitím vymezené doby života:
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();
}
Následující obslužná rutina delegování využívá a používá k IOperationScoped nastavení X-OPERATION-ID hlavičky pro odchozí požadavek:
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);
}
}
V souboru HttpRequestsSample ke stažení] přejděte na /Operation stránku a aktualizujte ji. Hodnota rozsahu požadavku se mění pro každý požadavek, ale hodnota oboru obslužné rutiny se mění jenom každých 5 sekund.
Obslužné rutiny mohou záviset na službách libovolného oboru. Služby, na které obslužné rutiny závisí, jsou uvolněny, když je obslužná rutina odstraněna.
Ke sdílení stavu jednotlivých žádostí s obslužnou rutinou zpráv použijte jeden z následujících přístupů:
- Předejte data obslužné rutině pomocí HttpRequestMessage.Properties.
- Pro IHttpContextAccessor přístup k aktuálnímu požadavku použijte .
- Vytvořte vlastní AsyncLocal<T> objekt úložiště pro předání dat.
Použití obslužných rutin založených na Polly
IHttpClientFactory se integruje s knihovnou třetí strany Polly. Polly je komplexní knihovna odolnosti a zpracování přechodných chyb pro .NET. Umožňuje vývojářům vyjadřovat zásady, jako jsou opakování, jistič, časový limit, izolace přepážek a záložní model, a to plynule a bezpečným způsobem pro přístup z více vláken.
K dispozici jsou metody rozšíření, které umožňují používat zásady Polly s HttpClient nakonfigurovanou instancí. Rozšíření Polly podporují přidávání obslužných rutin založených na Polly do klientů. Polly vyžaduje balíček NuGet Microsoft.Extensions.Http.Polly.
Zpracování přechodných chyb
K chybám obvykle dochází v případě přechodných externích volání HTTP. AddTransientHttpErrorPolicy umožňuje definovat zásady pro zpracování přechodných chyb. Zásady nakonfigurované pro AddTransientHttpErrorPolicy zpracování následujících odpovědí:
- HttpRequestException
- HTTP 5xx
- HTTP 408
AddTransientHttpErrorPolicy poskytuje přístup k objektu PolicyBuilder nakonfigurovanmu pro zpracování chyb představujících možnou přechodnou chybu:
public void ConfigureServices(IServiceCollection services)
{
services.AddHttpClient<UnreliableEndpointCallerService>()
.AddTransientHttpErrorPolicy(p =>
p.WaitAndRetryAsync(3, _ => TimeSpan.FromMilliseconds(600)));
// Remaining code deleted for brevity.
V předchozím kódu je WaitAndRetryAsync definována zásada. Neúspěšné požadavky se mezi pokusy zkusí až třikrát zopakovat se zpožděním 600 ms.
Dynamické výběr zásad
Metody rozšíření jsou k dispozici pro přidání obslužných rutin založených na Polly, například AddPolicyHandler . Následující přetížení AddPolicyHandler požadavek prověří a rozhodne, které zásady se mají použít:
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);
Pokud je v předchozím kódu odchozí požadavek HTTP GET, použije se časový limit 10 sekund. Pro jakoukoli jinou metodu HTTP se použije časový limit 30 sekund.
Přidání více obslužných rutin Polly
Zásady Polly se běžně vnořuje:
services.AddHttpClient("multiplepolicies")
.AddTransientHttpErrorPolicy(p => p.RetryAsync(3))
.AddTransientHttpErrorPolicy(
p => p.CircuitBreakerAsync(5, TimeSpan.FromSeconds(30)));
V předchozím příkladu:
- Přidávají se dvě obslužné rutiny.
- První obslužná rutina AddTransientHttpErrorPolicy používá k přidání zásady opakování. Neúspěšné požadavky se budou až třikrát zopakovat.
- Druhé volání
AddTransientHttpErrorPolicypřidá zásadu jističe. Další externí požadavky se zablokují po dobu 30 sekund, pokud se postupně pokusí o 5 neúspěšných pokusů. Zásady jističe jsou stavové. Všechna volání prostřednictvím tohoto klienta sdílejí stejný stav okruhu.
Přidání zásad z registru Polly
Přístup ke správě pravidelně používaných zásad je definovat je jednou a zaregistrovat je pomocí PolicyRegistry .
V následujícím kódu:
- Přidávají se "běžné" a "dlouhé" zásady.
- AddPolicyHandlerFromRegistry přidá z registru běžné a dlouhé zásady.
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.
Další informace o IHttpClientFactory integracích a Polly najdete na wikiwebu Polly.
HttpClient a správa doby života
Nová HttpClient instance se vrátí CreateClient pokaždé, když se volá v IHttpClientFactory . Vytvoří HttpMessageHandler se pro pojmenovaného klienta. Továrna spravuje životnost HttpMessageHandler instancí.
IHttpClientFactory fondy HttpMessageHandler instancí vytvořených továrnou, aby se snížila spotřeba prostředků. Instance se může znovu použít z fondu při vytváření nové instance, pokud její životnost HttpMessageHandler HttpClient nevyšla.
Sdružování obslužných rutin je žádoucí, protože každá obslužná rutina obvykle spravuje vlastní základní připojení HTTP. Vytvoření více obslužných rutin, než je potřeba, může vést ke zpoždění připojení. Některé obslužné rutiny také udržují připojení otevřená po neomezenou dobu, což může zabránit tomu, aby obslužná rutina reagovala na změny DNS (Domain Name System).
Výchozí doba života obslužné rutiny je dvě minuty. Výchozí hodnotu je možné přepsat pro jednoho pojmenovaného klienta:
public void ConfigureServices(IServiceCollection services)
{
services.AddHttpClient("extendedhandlerlifetime")
.SetHandlerLifetime(TimeSpan.FromMinutes(5));
// Remaining code deleted for brevity.
HttpClient instance je obecně možné považovat za objekty .NET, které nevyžadují vyřazení. Vyřazení zruší odchozí žádosti a zaručuje, že danou HttpClient instanci nelze použít po volání Dispose . IHttpClientFactory sleduje a odstraňuje prostředky používané HttpClient instancemi.
Udržování jediné HttpClient instance po dlouhou dobu je společný vzor, který se používá před zahájením IHttpClientFactory . Tento model se po migraci na nedá zbytečné IHttpClientFactory .
Alternativy k IHttpClientFactory
Použití IHttpClientFactory v aplikaci s podporou di se vyhne:
- Problémy s vyčerpáním prostředků díky sdružování
HttpMessageHandlerinstancí. - Zastaralé problémy se službou DNS cyklicky cyklických
HttpMessageHandlerinstancí v pravidelných intervalech.
Existují alternativní způsoby, jak vyřešit předchozí problémy pomocí dlouhotrvající SocketsHttpHandler instance.
- Vytvořte instanci aplikace,
SocketsHttpHandlerkdyž se aplikace spustí a použije se po celou dobu životnosti aplikace. - Proveďte konfiguraci PooledConnectionLifetime na odpovídající hodnotu na základě časů aktualizace DNS.
- Vytvořte
HttpClientinstancenew HttpClient(handler, disposeHandler: false)podle potřeby.
Předchozí přístupy vyřeší problémy se správou prostředků, které se IHttpClientFactory podobným způsobem vyřeší.
SocketsHttpHandlerSdílí připojení meziHttpClientinstancemi. Toto sdílení zabraňuje vyčerpání soketů.SocketsHttpHandlerCyklická připojení jsou na základě toho,PooledConnectionLifetimeaby se předešlo zastaralým problémům s DNS.
Cookiepracují
Instance ve fondu mají HttpMessageHandler za následek CookieContainer Sdílení objektů. Neočekávané CookieContainer Sdílení objektů často vede k nesprávnému kódu. U aplikací, které vyžadují cookie s, zvažte jednu z těchto akcí:
- Zákaz automatického cookie zpracování
- Opakované
IHttpClientFactory
Volání ConfigurePrimaryHttpMessageHandler pro zakázání automatického cookie zpracování:
services.AddHttpClient("configured-disable-automatic-cookies")
.ConfigurePrimaryHttpMessageHandler(() =>
{
return new HttpClientHandler()
{
UseCookies = false,
};
});
protokolování
Klienti vytvoření prostřednictvím IHttpClientFactory záznamu zprávy protokolu pro všechny požadavky. V konfiguraci protokolování povolte příslušnou úroveň informací, aby se zobrazily výchozí zprávy protokolu. Další protokolování, jako je protokolování hlaviček požadavků, je zahrnuté jenom na úrovni trasování.
Kategorie protokolu použitá pro každého klienta zahrnuje název klienta. Klient s názvem MyNamedClient například protokoluje zprávy s kategorií "System .NET. http. HttpClient. MyNamedClient. LogicalHandler". Zprávy s příponou LogicalHandler se vyskytují mimo kanál obslužné rutiny žádosti. V žádosti se zprávy protokolují předtím, než je zpracuje kterákoli jiný obslužná rutina v kanálu. Na základě odpovědi se zprávy zaprotokolují, až ostatní obslužné rutiny kanálu obdrží odpověď.
K protokolování dojde také uvnitř kanálu obslužné rutiny žádosti. V příkladu MyNamedClient jsou tyto zprávy protokolovány pomocí kategorie log "System .NET. http. HttpClient. MyNamedClient. ClientHandler". Pro požadavek se k tomu dochází po spuštění všech ostatních obslužných rutin a bezprostředně před odesláním žádosti. V odpovědi Toto protokolování zahrnuje stav odpovědi předtím, než se přepošle zpět přes kanál obslužné rutiny.
Povolení protokolování mimo kanál a uvnitř kanálu umožňuje kontrolu změn provedených ostatními obslužnými rutinami kanálu. To může zahrnovat změny hlaviček žádostí nebo kód stavu odpovědi.
Zahrnutí názvu klienta do kategorie protokolu umožňuje filtrování protokolu pro konkrétní pojmenované klienty.
Konfigurace HttpMessageHandler
Může být nutné řídit konfiguraci vnitřního HttpMessageHandler používaného klienta.
IHttpClientBuilderPři přidávání pojmenovaných nebo typových klientů se vrátí. ConfigurePrimaryHttpMessageHandlerMetodu rozšíření lze použít k definování delegáta. Delegát slouží k vytvoření a konfiguraci primárního HttpMessageHandler používaného klienta:
public void ConfigureServices(IServiceCollection services)
{
services.AddHttpClient("configured-inner-handler")
.ConfigurePrimaryHttpMessageHandler(() =>
{
return new HttpClientHandler()
{
AllowAutoRedirect = false,
UseDefaultCredentials = true
};
});
// Remaining code deleted for brevity.
Použití IHttpClientFactory v konzolové aplikaci
V aplikaci konzoly přidejte do projektu následující odkazy na balíček:
V následujícím příkladu:
- IHttpClientFactory je zaregistrován v kontejneru služby obecného hostitele .
MyServiceVytvoří instanci klientské továrny ze služby, která se používá k vytvořeníHttpClient.HttpClientslouží k načtení webové stránky.Mainvytvoří obor pro provedeníGetPagemetody služby a zapíše první 500 znaků obsahu webové stránky do konzoly.
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}";
}
}
}
}
Middleware šíření hlaviček
šíření hlaviček je ASP.NET Core middleware pro šíření hlaviček protokolu http z příchozího požadavku do odchozích požadavků klienta http. Použití rozšíření hlavičky:
Odkázat na balíček Microsoft. AspNetCore. HeaderPropagation .
Konfigurace middlewaru a
HttpClientvStartup: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(); }); }Klient zahrnuje nakonfigurovaná záhlaví na odchozích žádostech:
var client = clientFactory.CreateClient("MyForwardingClient"); var response = client.GetAsync(...);