HttpContext gebruiken in ASP.NET Core
Notitie
Dit is niet de nieuwste versie van dit artikel. Zie de .NET 9-versie van dit artikelvoor de huidige release.
Waarschuwing
Deze versie van ASP.NET Core wordt niet meer ondersteund. Zie de .NET- en .NET Core-ondersteuningsbeleidvoor meer informatie. Zie de .NET 9-versie van dit artikelvoor de huidige release.
Belangrijk
Deze informatie heeft betrekking op een pre-releaseproduct dat aanzienlijk kan worden gewijzigd voordat het commercieel wordt uitgebracht. Microsoft geeft geen garanties, uitdrukkelijk of impliciet, met betrekking tot de informatie die hier wordt verstrekt.
Zie de .NET 9-versie van dit artikelvoor de huidige release.
HttpContext bevat alle informatie over een afzonderlijke HTTP-aanvraag en -reactie. Een HttpContext
-exemplaar wordt geïnitialiseerd wanneer een HTTP-aanvraag wordt ontvangen. Het HttpContext
-exemplaar is toegankelijk via middleware en app-frameworks, zoals Blazor Web Apps, Web-API-controllers, Razor Pagina's, SignalR, gRPC en meer.
HttpRequest
HttpContext.Request biedt toegang tot HttpRequest.
HttpRequest
informatie heeft over de binnenkomende HTTP-aanvraag en deze wordt geïnitialiseerd wanneer een HTTP-aanvraag door de server wordt ontvangen.
HttpRequest
is niet alleen-lezen en middleware kan verzoekwaarden in de middleware-pijplijn wijzigen.
Veelgebruikte leden op HttpRequest
zijn onder andere:
Eigenschap | Beschrijving | Voorbeeld |
---|---|---|
HttpRequest.Path | Het aanvraagpad. | /en/article/getstarted |
HttpRequest.Method | De aanvraagmethode. | GET |
HttpRequest.Headers | Een verzameling verzoekheaders. | user-agent=Edge x-custom-header=MyValue |
HttpRequest.RouteValues | Een verzameling routewaarden. De verzameling wordt ingesteld wanneer de aanvraag overeenkomt met een route. | language=en article=getstarted |
HttpRequest.Query | Een verzameling querywaarden die worden geparseerd uit QueryString. | filter=hello page=1 |
httpRequest.ReadFormAsync() | Een methode die de hoofdtekst van de aanvraag als formulier leest en een verzameling formulierwaarden retourneert. Zie Prefer ReadFormAsync over Request.Formvoor informatie over waarom ReadFormAsync moet worden gebruikt voor toegang tot formuliergegevens. |
email=user@contoso.com |
HttpRequest.Body | Een Stream voor het lezen van de aanvraagtekst. | UTF-8 JSON-payload |
Aanvraagheaders ophalen
HttpRequest.Headers biedt toegang tot de aanvraagheaders die worden verzonden met de HTTP-aanvraag. Er zijn twee manieren om toegang te krijgen tot headers met behulp van deze verzameling:
- Geef de naam van de header op voor de indexeerfunctie in de headerverzameling. De naam van de header is niet hoofdlettergevoelig. De indexeerfunctie heeft toegang tot elke headerwaarde.
- De headerverzameling bevat ook eigenschappen voor het ophalen en instellen van veelgebruikte HTTP-headers. De eigenschappen bieden een snelle, op IntelliSense gestuurde manier om toegang te krijgen tot headers.
var builder = WebApplication.CreateBuilder(args);
var app = builder.Build();
app.MapGet("/", (HttpRequest request) =>
{
var userAgent = request.Headers.UserAgent;
var customHeader = request.Headers["x-custom-header"];
return Results.Ok(new { userAgent = userAgent, customHeader = customHeader });
});
app.Run();
Zie Een kort overzicht van StringValuesvoor informatie over het efficiënt verwerken van headers die meer dan één keer worden weergegeven.
Hoofdtekst van aanvraag lezen
Een HTTP-aanvraag kan een aanvraagbody bevatten. De hoofdtekst van de aanvraag is data die is geassocieerd met de aanvraag, zoals de inhoud van een HTML-formulier, UTF-8 JSON-gegevens of een bestand.
HttpRequest.Body kan de aanvraagtekst worden gelezen met Stream:
var builder = WebApplication.CreateBuilder(args);
var app = builder.Build();
app.MapPost("/uploadstream", async (IConfiguration config, HttpContext context) =>
{
var filePath = Path.Combine(config["StoredFilesPath"], Path.GetRandomFileName());
await using var writeStream = File.Create(filePath);
await context.Request.Body.CopyToAsync(writeStream);
});
app.Run();
HttpRequest.Body
kan rechtstreeks worden gelezen of gebruikt met andere API's die stream accepteren.
Notitie
Minimale API's ondersteunt het rechtstreeks binden van HttpRequest.Body aan een Stream parameter.
Buffering van aanvraagbody inschakelen
De hoofdtekst van de aanvraag kan slechts eenmaal worden gelezen, van begin tot eind. Het uitsluitend voorwaarts lezen van de aanvraagbody voorkomt de last van het bufferen van de gehele aanvraagbody en vermindert het geheugengebruik. In sommige scenario's is het echter nodig om de aanvraagtekst meerdere keren te lezen. Middleware moet bijvoorbeeld de hoofdtekst van de aanvraag lezen en deze vervolgens terugspoelen, zodat deze beschikbaar is voor het eindpunt.
De EnableBuffering-extensiemethode maakt buffering van de HOOFDtekst van de HTTP-aanvraag mogelijk en is de aanbevolen manier om meerdere leesbewerkingen in te schakelen. Omdat een aanvraag elke grootte kan hebben, ondersteunt EnableBuffering
opties voor het bufferen van grote aanvraagbody's op schijf of het volledig weigeren ervan.
De middleware in het volgende voorbeeld:
- Hiermee worden meerdere leesbewerkingen met
EnableBuffering
ingeschakeld. Deze moet worden aangeroepen voordat je de aanvraagtekst leest. - Leest de hoofdtekst van de aanvraag.
- Hiermee wordt de hoofdtekst van de aanvraag teruggespoelen naar het begin, zodat andere middleware of het eindpunt deze kunnen lezen.
var builder = WebApplication.CreateBuilder(args);
var app = builder.Build();
app.Use(async (context, next) =>
{
context.Request.EnableBuffering();
await ReadRequestBody(context.Request.Body);
context.Request.Body.Position = 0;
await next.Invoke();
});
app.Run();
BodyReader
Een alternatieve manier om de hoofdtekst van de aanvraag te lezen, is door de eigenschap HttpRequest.BodyReader te gebruiken. Met de eigenschap BodyReader
wordt de request body weergegeven als een PipeReader. Deze API is afkomstig van I/O-pijplijnen, een geavanceerde, krachtige manier om de aanvraagbody te lezen.
De lezer heeft rechtstreeks toegang tot de hoofdtekst van de aanvraag en beheert het geheugen namens de beller. In tegenstelling tot HttpRequest.Body
kopieert de lezer geen aanvraaggegevens naar een buffer. Een lezer is echter ingewikkelder te gebruiken dan een stream en moet voorzichtig worden gebruikt.
Zie voor informatie over het lezen van inhoud uit
HttpResponse
HttpContext.Response biedt toegang tot HttpResponse.
HttpResponse
wordt gebruikt om informatie in te stellen over het HTTP-antwoord dat naar de client wordt verzonden.
Veelgebruikte leden op HttpResponse
zijn onder andere:
Eigenschap | Beschrijving | Voorbeeld |
---|---|---|
HttpResponse.StatusCode | De antwoordcode. Moet worden ingesteld voordat u naar de hoofdtekst van het antwoord schrijft. | 200 |
HttpResponse.ContentType | Het antwoord content-type koptekst. Moet worden ingesteld voordat u naar de hoofdtekst van het antwoord schrijft. |
application/json |
HttpResponse.Headers | Een verzameling antwoordheaders. Moet worden ingesteld voordat u naar de hoofdtekst van het antwoord schrijft. | server=Kestrel x-custom-header=MyValue |
HttpResponse.Body | Een Stream voor het schrijven van de hoofdtekst van het antwoord. | Gegenereerde webpagina |
Antwoordheaders instellen
HttpResponse.Headers biedt toegang tot de antwoordheaders die worden verzonden met het HTTP-antwoord. Er zijn twee manieren om toegang te krijgen tot headers met behulp van deze verzameling:
- Geef de naam van de header op voor de indexeerfunctie in de headerverzameling. De naam van de header is niet hoofdlettergevoelig. De indexeerfunctie heeft toegang tot elke headerwaarde.
- Gebruik de eigenschappen van de headerverzameling voor het ophalen en instellen van veelgebruikte HTTP-headers. De eigenschappen bieden een snelle manier om, gestuurd door IntelliSense, toegang te krijgen tot headers.
var builder = WebApplication.CreateBuilder(args);
var app = builder.Build();
app.MapGet("/", (HttpResponse response) =>
{
response.Headers.CacheControl = "no-cache";
response.Headers["x-custom-header"] = "Custom value";
return Results.File(File.OpenRead("helloworld.txt"));
});
app.Run();
Een app kan headers niet wijzigen nadat het antwoord is gestart. Zodra het antwoord is gestart, worden de headers naar de client verzonden. Een antwoord wordt gestart door de hoofdtekst van het antwoord te leegmaken of HttpResponse.StartAsync(CancellationToken)aan te roepen. De eigenschap HttpResponse.HasStarted geeft aan of het antwoord is gestart. Er treedt een fout op bij het wijzigen van headers nadat het antwoord is gestart:
System.InvalidOperationException: Headers zijn alleen-lezen, antwoord is al gestart.
Notitie
Tenzij reactiebuffering is ingeschakeld, worden alle schrijfbewerkingen (bijvoorbeeld WriteAsync) de hoofdtekst van het antwoord intern leeggemaakt en wordt het antwoord gemarkeerd als gestart. Reactiebuffering is standaard uitgeschakeld.
Schrijf antwoordtekst
Een HTTP-antwoord kan een antwoordtekst bevatten. De hoofdtekst van het antwoord bevat gegevens die zijn gekoppeld aan het antwoord, zoals gegenereerde webpagina-inhoud, UTF-8 JSON-nettolading of een bestand.
De hoofdtekst van het antwoord kan met Streamworden geschreven door HttpResponse.Body.
var builder = WebApplication.CreateBuilder(args);
var app = builder.Build();
app.MapPost("/downloadfile", async (IConfiguration config, HttpContext context) =>
{
var filePath = Path.Combine(config["StoredFilesPath"], "helloworld.txt");
await using var fileStream = File.OpenRead(filePath);
await fileStream.CopyToAsync(context.Response.Body);
});
app.Run();
HttpResponse.Body
kan rechtstreeks worden geschreven of worden gebruikt met andere API's die naar een stream schrijven.
BodyWriter
U kunt de hoofdtekst van het antwoord ook schrijven door de eigenschap HttpResponse.BodyWriter te gebruiken. Met de eigenschap BodyWriter
wordt de hoofdtekst van het antwoord weergegeven als een PipeWriter. Deze API is afkomstig van I/O-pijplijnenen het is een geavanceerde, krachtige manier om het antwoord te schrijven.
De schrijver biedt directe toegang tot de hoofdtekst van het antwoord en beheert het geheugen namens de beller. In tegenstelling tot HttpResponse.Body
, kopieert de schrijfbewerking geen aanvraaggegevens naar een buffer. Een schrijver is echter ingewikkelder om te gebruiken dan een stream en schrijfcode moet grondig worden getest.
Zie voor informatie over het schrijven van inhoud naar BodyWriter
in I/O-pijplijnen PipeWriter.
Antwoordtrailers instellen
HTTP/2 en HTTP/3 ondersteunen antwoordtrailers. Trailers zijn headers die met het antwoord worden verzonden nadat de hoofdtekst van het antwoord is voltooid. Omdat trailers na de antwoordbody worden verzonden, kunnen trailers op elk gewenst moment aan het antwoord worden toegevoegd.
De volgende code stelt trailers in met behulp van AppendTrailer:
var builder = WebApplication.CreateBuilder(args);
var app = builder.Build();
app.MapGet("/", (HttpResponse response) =>
{
// Write body
response.WriteAsync("Hello world");
if (response.SupportsTrailers())
{
response.AppendTrailer("trailername", "TrailerValue");
}
});
app.Run();
RequestAborted
Het HttpContext.RequestAborted annuleringstoken kan worden gebruikt om te melden dat de HTTP-aanvraag is afgebroken door de client of server. Het annuleringstoken moet worden doorgegeven aan langlopende taken, zodat ze kunnen worden geannuleerd als de aanvraag wordt afgebroken. Bijvoorbeeld het afbreken van een databasequery of HTTP-aanvraag om gegevens op te halen die in het antwoord moeten worden geretourneerd.
var builder = WebApplication.CreateBuilder(args);
var app = builder.Build();
var httpClient = new HttpClient();
app.MapPost("/books/{bookId}", async (int bookId, HttpContext context) =>
{
var stream = await httpClient.GetStreamAsync(
$"http://contoso/books/{bookId}.json", context.RequestAborted);
// Proxy the response as JSON
return Results.Stream(stream, "application/json");
});
app.Run();
Het RequestAborted
annuleringstoken hoeft niet te worden gebruikt voor leesbewerkingen van de aanvraagbody, omdat leesbewerkingen altijd onmiddellijk worden gegenereerd wanneer de aanvraag wordt afgebroken. Het RequestAborted
token is meestal ook niet nodig bij het schrijven van antwoordteksten, omdat schrijfbewerkingen onmiddellijk no-op wanneer de aanvraag wordt afgebroken.
In sommige gevallen kan het doorgeven van de RequestAborted
-token aan schrijfbewerkingen een handige manier zijn om een schrijflus voortijdig af te sluiten met een OperationCanceledException. Het is echter gebruikelijker om het RequestAborted
token door te geven aan asynchrone bewerkingen die verantwoordelijk zijn voor het ophalen van de inhoud van de antwoordtekst.
Notitie
Minimale API's ondersteunt het rechtstreeks binden van HttpContext.RequestAborted aan een CancellationToken parameter.
Abort()
De methode HttpContext.Abort() kan worden gebruikt om een HTTP-aanvraag van de server af te breken. Wanneer de HTTP-aanvraag wordt afgebroken, wordt het HttpContext.RequestAborted annuleringstoken geactiveerd en wordt er een melding verzonden naar de client dat de server de aanvraag heeft afgebroken.
De middleware in het volgende voorbeeld:
- Voegt een aangepaste controle toe voor schadelijke aanvragen.
- Hiermee wordt de HTTP-aanvraag afgebroken als de aanvraag schadelijk is.
var builder = WebApplication.CreateBuilder(args);
var app = builder.Build();
app.Use(async (context, next) =>
{
if (RequestAppearsMalicious(context.Request))
{
// Malicious requests don't even deserve an error response (e.g. 400).
context.Abort();
return;
}
await next.Invoke();
});
app.Run();
User
De eigenschap HttpContext.User wordt gebruikt om de gebruiker, vertegenwoordigd door ClaimsPrincipal, voor de aanvraag op te halen of in te stellen. De ClaimsPrincipal wordt doorgaans ingesteld door ASP.NET Core-verificatie.
var builder = WebApplication.CreateBuilder(args);
var app = builder.Build();
app.MapGet("/user/current", [Authorize] async (HttpContext context) =>
{
var user = await GetUserAsync(context.User.Identity.Name);
return Results.Ok(user);
});
app.Run();
Notitie
Minimale API's ondersteunt het rechtstreeks binden van HttpContext.User aan een ClaimsPrincipal parameter.
Features
De eigenschap HttpContext.Features biedt toegang tot de verzameling functie-interfaces voor de huidige aanvraag. Omdat de functieverzameling kan worden gedempt, zelfs binnen de context van een aanvraag, kan middleware worden gebruikt om de verzameling te wijzigen en ondersteuning toe te voegen voor aanvullende functies. Sommige geavanceerde functies zijn alleen beschikbaar door toegang te krijgen tot de bijbehorende interface via de functieverzameling.
Het volgende voorbeeld:
- Hiermee haalt u IHttpMinRequestBodyDataRateFeature op uit de functiesverzameling.
- Hiermee stelt u MinDataRate in op null. Hiermee verwijdert u de minimale gegevenssnelheid waarmee de aanvraagtekst door de client moet worden verzonden voor deze HTTP-aanvraag.
var builder = WebApplication.CreateBuilder(args);
var app = builder.Build();
app.MapGet("/long-running-stream", async (HttpContext context) =>
{
var feature = context.Features.Get<IHttpMinRequestBodyDataRateFeature>();
if (feature != null)
{
feature.MinDataRate = null;
}
// await and read long-running stream from request body.
await Task.Yield();
});
app.Run();
Zie Aanvraagfuncties in ASP.NET Corevoor meer informatie over het gebruik van aanvraagfuncties en HttpContext
.
HttpContext is geen thread veilig
In dit artikel wordt voornamelijk besproken hoe u HttpContext
gebruikt in de aanvraag- en antwoordstroom van Blazor Web App onderdelen, Razor Pagina's, controllers, middleware, enzovoort. Houd rekening met het volgende wanneer u HttpContext
buiten de aanvraag- en antwoordstroom gebruikt:
- De
HttpContext
is NIET thread veilig. Als u deze opent vanuit meerdere threads, kan dit leiden tot onvoorspelbare resultaten, zoals uitzonderingen en beschadiging van gegevens. - De IHttpContextAccessor interface moet voorzichtig worden gebruikt. Zoals altijd moet de
HttpContext
niet buiten de aanvraagstroom worden vastgelegd.IHttpContextAccessor
:- Is afhankelijk van AsyncLocal<T>, wat een negatieve invloed kan hebben op asynchrone aanroepen.
- Hiermee maakt u een afhankelijkheid van de 'omgevingsstatus' die het testen moeilijker kan maken.
-
IHttpContextAccessor.HttpContext kan worden
null
als deze buiten de aanvraagstroom wordt geopend. - Als u toegang wilt krijgen tot gegevens uit
HttpContext
buiten de aanvraagstroom, kopieert u de informatie in de aanvraagstroom. Zorg ervoor dat u de werkelijke gegevens en niet alleen verwijzingen kopieert. In plaats van bijvoorbeeld een verwijzing naar eenIHeaderDictionary
te kopiëren, kopieert u de relevante headerwaarden of kopieert u de hele woordenlijstsleutel per sleutel voordat u de aanvraagstroom verlaat. - Leg
IHttpContextAccessor.HttpContext
niet vast in een constructor.
In het volgende voorbeeld worden GitHub-vertakkingen gelogd wanneer ze worden opgevraagd van het /branch
-eindpunt:
using System.Text.Json;
using HttpContextInBackgroundThread;
using Microsoft.Net.Http.Headers;
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddHttpContextAccessor();
builder.Services.AddHostedService<PeriodicBranchesLoggerService>();
builder.Services.AddHttpClient("GitHub", httpClient =>
{
httpClient.BaseAddress = new Uri("https://api.github.com/");
// The GitHub API requires two headers. The Use-Agent header is added
// dynamically through UserAgentHeaderHandler
httpClient.DefaultRequestHeaders.Add(
HeaderNames.Accept, "application/vnd.github.v3+json");
}).AddHttpMessageHandler<UserAgentHeaderHandler>();
builder.Services.AddTransient<UserAgentHeaderHandler>();
var app = builder.Build();
app.MapGet("/", () => "Hello World!");
app.MapGet("/branches", async (IHttpClientFactory httpClientFactory,
HttpContext context, Logger<Program> logger) =>
{
var httpClient = httpClientFactory.CreateClient("GitHub");
var httpResponseMessage = await httpClient.GetAsync(
"repos/dotnet/AspNetCore.Docs/branches");
if (!httpResponseMessage.IsSuccessStatusCode)
return Results.BadRequest();
await using var contentStream =
await httpResponseMessage.Content.ReadAsStreamAsync();
var response = await JsonSerializer.DeserializeAsync
<IEnumerable<GitHubBranch>>(contentStream);
app.Logger.LogInformation($"/branches request: " +
$"{JsonSerializer.Serialize(response)}");
return Results.Ok(response);
});
app.Run();
Voor de GitHub-API zijn twee headers vereist. De User-Agent
koptekst wordt dynamisch toegevoegd door de UserAgentHeaderHandler
:
using System.Text.Json;
using HttpContextInBackgroundThread;
using Microsoft.Net.Http.Headers;
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddHttpContextAccessor();
builder.Services.AddHostedService<PeriodicBranchesLoggerService>();
builder.Services.AddHttpClient("GitHub", httpClient =>
{
httpClient.BaseAddress = new Uri("https://api.github.com/");
// The GitHub API requires two headers. The Use-Agent header is added
// dynamically through UserAgentHeaderHandler
httpClient.DefaultRequestHeaders.Add(
HeaderNames.Accept, "application/vnd.github.v3+json");
}).AddHttpMessageHandler<UserAgentHeaderHandler>();
builder.Services.AddTransient<UserAgentHeaderHandler>();
var app = builder.Build();
app.MapGet("/", () => "Hello World!");
app.MapGet("/branches", async (IHttpClientFactory httpClientFactory,
HttpContext context, Logger<Program> logger) =>
{
var httpClient = httpClientFactory.CreateClient("GitHub");
var httpResponseMessage = await httpClient.GetAsync(
"repos/dotnet/AspNetCore.Docs/branches");
if (!httpResponseMessage.IsSuccessStatusCode)
return Results.BadRequest();
await using var contentStream =
await httpResponseMessage.Content.ReadAsStreamAsync();
var response = await JsonSerializer.DeserializeAsync
<IEnumerable<GitHubBranch>>(contentStream);
app.Logger.LogInformation($"/branches request: " +
$"{JsonSerializer.Serialize(response)}");
return Results.Ok(response);
});
app.Run();
De UserAgentHeaderHandler
:
using Microsoft.Net.Http.Headers;
namespace HttpContextInBackgroundThread;
public class UserAgentHeaderHandler : DelegatingHandler
{
private readonly IHttpContextAccessor _httpContextAccessor;
private readonly ILogger _logger;
public UserAgentHeaderHandler(IHttpContextAccessor httpContextAccessor,
ILogger<UserAgentHeaderHandler> logger)
{
_httpContextAccessor = httpContextAccessor;
_logger = logger;
}
protected override async Task<HttpResponseMessage>
SendAsync(HttpRequestMessage request,
CancellationToken cancellationToken)
{
var contextRequest = _httpContextAccessor.HttpContext?.Request;
string? userAgentString = contextRequest?.Headers["user-agent"].ToString();
if (string.IsNullOrEmpty(userAgentString))
{
userAgentString = "Unknown";
}
request.Headers.Add(HeaderNames.UserAgent, userAgentString);
_logger.LogInformation($"User-Agent: {userAgentString}");
return await base.SendAsync(request, cancellationToken);
}
}
Wanneer de HttpContext
in de voorgaande code is null
, wordt de userAgent
tekenreeks ingesteld op "Unknown"
. Indien mogelijk moet HttpContext
expliciet worden doorgegeven aan de service. Expliciet HttpContext
gegevens doorgeven:
- Maakt de service-API beter bruikbaar buiten de aanvraagstroom.
- Is beter voor prestaties.
- Maakt de code gemakkelijker te begrijpen en te redeneren over dan afhankelijk te zijn van de omgevingsstatus.
Wanneer de service toegang moet krijgen tot HttpContext
, moet deze rekening houden met de mogelijkheid dat HttpContext
wordt null
wanneer deze niet wordt aangeroepen vanuit een aanvraagthread.
De toepassing bevat ook PeriodicBranchesLoggerService
, waarmee de geopende GitHub-vertakkingen van de opgegeven opslagplaats elke 30 seconden worden vastgelegd:
using System.Text.Json;
namespace HttpContextInBackgroundThread;
public class PeriodicBranchesLoggerService : BackgroundService
{
private readonly IHttpClientFactory _httpClientFactory;
private readonly ILogger _logger;
private readonly PeriodicTimer _timer;
public PeriodicBranchesLoggerService(IHttpClientFactory httpClientFactory,
ILogger<PeriodicBranchesLoggerService> logger)
{
_httpClientFactory = httpClientFactory;
_logger = logger;
_timer = new PeriodicTimer(TimeSpan.FromSeconds(30));
}
protected override async Task ExecuteAsync(CancellationToken stoppingToken)
{
while (await _timer.WaitForNextTickAsync(stoppingToken))
{
try
{
// Cancel sending the request to sync branches if it takes too long
// rather than miss sending the next request scheduled 30 seconds from now.
// Having a single loop prevents this service from sending an unbounded
// number of requests simultaneously.
using var syncTokenSource = CancellationTokenSource.CreateLinkedTokenSource(stoppingToken);
syncTokenSource.CancelAfter(TimeSpan.FromSeconds(30));
var httpClient = _httpClientFactory.CreateClient("GitHub");
var httpResponseMessage = await httpClient.GetAsync("repos/dotnet/AspNetCore.Docs/branches",
stoppingToken);
if (httpResponseMessage.IsSuccessStatusCode)
{
await using var contentStream =
await httpResponseMessage.Content.ReadAsStreamAsync(stoppingToken);
// Sync the response with preferred datastore.
var response = await JsonSerializer.DeserializeAsync<
IEnumerable<GitHubBranch>>(contentStream, cancellationToken: stoppingToken);
_logger.LogInformation(
$"Branch sync successful! Response: {JsonSerializer.Serialize(response)}");
}
else
{
_logger.LogError(1, $"Branch sync failed! HTTP status code: {httpResponseMessage.StatusCode}");
}
}
catch (Exception ex)
{
_logger.LogError(1, ex, "Branch sync failed!");
}
}
}
public override Task StopAsync(CancellationToken stoppingToken)
{
// This will cause any active call to WaitForNextTickAsync() to return false immediately.
_timer.Dispose();
// This will cancel the stoppingToken and await ExecuteAsync(stoppingToken).
return base.StopAsync(stoppingToken);
}
}
PeriodicBranchesLoggerService
is een gehoste service, die buiten de aanvraag- en antwoordstroom wordt uitgevoerd. Logboekregistratie van de PeriodicBranchesLoggerService
heeft een nulwaarde HttpContext
. De PeriodicBranchesLoggerService
was geschreven om niet afhankelijk te zijn van de HttpContext
.
using System.Text.Json;
using HttpContextInBackgroundThread;
using Microsoft.Net.Http.Headers;
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddHttpContextAccessor();
builder.Services.AddHostedService<PeriodicBranchesLoggerService>();
builder.Services.AddHttpClient("GitHub", httpClient =>
{
Aanvullende informatiebronnen
Voor meer informatie over toegang tot HttpContext
, zie Toegang tot HttpContext in ASP.NET Core.