Remarque
L’accès à cette page nécessite une autorisation. Vous pouvez essayer de vous connecter ou de modifier des répertoires.
L’accès à cette page nécessite une autorisation. Vous pouvez essayer de modifier des répertoires.
Par Tom Dykstra
Les applications peuvent appliquer des limites de délai d’attente sélectivement aux requêtes. ASP.NET serveurs Principaux ne le font pas par défaut, car les temps de traitement des demandes varient considérablement par scénario. Par exemple, les webSockets, les fichiers statiques et l’appel d’API coûteuses nécessitent chacun une limite de délai d’attente différente. Par conséquent, ASP.NET Core fournit un intergiciel qui configure les délais d’expiration par point de terminaison ainsi qu’un délai global.
Lorsqu’une limite de délai d’attente est atteinte, une CancellationToken valeur HttpContext.RequestAborted est IsCancellationRequested définie truesur .
Abort() n’est pas automatiquement appelé sur la demande, de sorte que l’application peut toujours produire une réponse de réussite ou d’échec. Le comportement par défaut si l’application ne gère pas l’exception et produit une réponse consiste à retourner le code d’état 504.
Cet article explique comment configurer l’intergiciel de délai d’attente. L’intergiciel de délai d’expiration peut être utilisé dans tous les types d’applications ASP.NET Principales : API minimale, API web avec contrôleurs, MVC et Razor Pages. L’exemple d’application est une API minimale, mais chaque fonctionnalité de délai d’expiration illustrée est également prise en charge dans les autres types d’application.
Les délais d’expiration des demandes se trouvent dans l’espace Microsoft.AspNetCore.Http.Timeouts de noms.
Note: Lorsqu’une application s’exécute en mode débogage, l’intergiciel de délai d’expiration ne se déclenche pas. Ce comportement est le même que pour Kestrel les délais d’expiration. Pour tester les délais d’expiration, exécutez l’application sans le débogueur attaché.
Ajouter le middleware à l’application
Ajoutez le middleware de délai d’expiration de la requête à la collection de services en appelant AddRequestTimeouts.
Ajoutez le middleware au pipeline de traitement des demandes en appelant UseRequestTimeouts.
Note
- Dans les applications qui appellent UseRoutingexplicitement ,
UseRequestTimeoutsdoivent être appelées aprèsUseRouting.
L’ajout du middleware à l’application ne démarre pas automatiquement le déclenchement des délais d’expiration. Les limites de délai d’expiration doivent être configurées explicitement.
Configurer un point de terminaison ou une page
Pour les applications API minimales, configurez un point de terminaison pour le délai d’expiration en appelant WithRequestTimeoutou en appliquant l’attribut [RequestTimeout] , comme illustré dans l’exemple suivant :
using Microsoft.AspNetCore.Http.Timeouts;
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddRequestTimeouts();
var app = builder.Build();
app.UseRequestTimeouts();
app.MapGet("/", async (HttpContext context) => {
try
{
await Task.Delay(TimeSpan.FromSeconds(10), context.RequestAborted);
}
catch (TaskCanceledException)
{
return Results.Content("Timeout!", "text/plain");
}
return Results.Content("No timeout!", "text/plain");
}).WithRequestTimeout(TimeSpan.FromSeconds(2));
// Returns "Timeout!"
app.MapGet("/attribute",
[RequestTimeout(milliseconds: 2000)] async (HttpContext context) => {
try
{
await Task.Delay(TimeSpan.FromSeconds(10), context.RequestAborted);
}
catch (TaskCanceledException)
{
return Results.Content("Timeout!", "text/plain");
}
return Results.Content("No timeout!", "text/plain");
});
// Returns "Timeout!"
app.Run();
Pour les applications avec des contrôleurs, appliquez l’attribut [RequestTimeout] à la méthode d’action ou à la classe de contrôleur. Pour Razor les applications Pages, appliquez l’attribut à la Razor classe de page.
Configurer plusieurs points de terminaison ou pages
Créez des stratégies nommées pour spécifier la configuration du délai d’expiration qui s’applique à plusieurs points de terminaison. Ajoutez une stratégie en appelant AddPolicy:
builder.Services.AddRequestTimeouts(options => {
options.DefaultPolicy =
new RequestTimeoutPolicy { Timeout = TimeSpan.FromMilliseconds(1500) };
options.AddPolicy("MyPolicy", TimeSpan.FromSeconds(2));
});
Un délai d’expiration peut être spécifié pour un point de terminaison par nom de stratégie :
app.MapGet("/namedpolicy", async (HttpContext context) => {
try
{
await Task.Delay(TimeSpan.FromSeconds(10), context.RequestAborted);
}
catch (TaskCanceledException)
{
return Results.Content("Timeout!", "text/plain");
}
return Results.Content("No timeout!", "text/plain");
}).WithRequestTimeout("MyPolicy");
// Returns "Timeout!"
L’attribut [RequestTimeout] peut également être utilisé pour spécifier une stratégie nommée.
Définir la stratégie globale de délai d’expiration par défaut
Spécifiez une stratégie pour la configuration globale du délai d’expiration par défaut :
builder.Services.AddRequestTimeouts(options => {
options.DefaultPolicy =
new RequestTimeoutPolicy { Timeout = TimeSpan.FromMilliseconds(1500) };
options.AddPolicy("MyPolicy", TimeSpan.FromSeconds(2));
});
Le délai d’expiration par défaut s’applique aux points de terminaison qui n’ont pas de délai d’expiration spécifié. Le code de point de terminaison suivant vérifie un délai d’expiration, même s’il n’appelle pas la méthode d’extension ou n’applique pas l’attribut. La configuration globale du délai d’expiration s’applique, de sorte que le code recherche un délai d’expiration :
app.MapGet("/", async (HttpContext context) => {
try
{
await Task.Delay(TimeSpan.FromSeconds(10), context.RequestAborted);
}
catch
{
return Results.Content("Timeout!", "text/plain");
}
return Results.Content("No timeout!", "text/plain");
});
// Returns "Timeout!" due to default policy.
Spécifier le code d’état dans une stratégie
La RequestTimeoutPolicy classe a une propriété qui peut définir automatiquement le code d’état lorsqu’un délai d’expiration est déclenché.
builder.Services.AddRequestTimeouts(options => {
options.DefaultPolicy = new RequestTimeoutPolicy {
Timeout = TimeSpan.FromMilliseconds(1000),
TimeoutStatusCode = 503
};
options.AddPolicy("MyPolicy2", new RequestTimeoutPolicy {
Timeout = TimeSpan.FromMilliseconds(1000),
WriteTimeoutResponse = async (HttpContext context) => {
context.Response.ContentType = "text/plain";
await context.Response.WriteAsync("Timeout from MyPolicy2!");
}
});
});
app.MapGet("/", async (HttpContext context) => {
try
{
await Task.Delay(TimeSpan.FromSeconds(10), context.RequestAborted);
}
catch (TaskCanceledException)
{
throw;
}
return Results.Content("No timeout!", "text/plain");
});
// Returns status code 503 due to default policy.
Utiliser un délégué dans une stratégie
La RequestTimeoutPolicy classe a une WriteTimeoutResponse propriété qui peut être utilisée pour personnaliser la réponse lorsqu’un délai d’expiration est déclenché.
builder.Services.AddRequestTimeouts(options => {
options.DefaultPolicy = new RequestTimeoutPolicy {
Timeout = TimeSpan.FromMilliseconds(1000),
TimeoutStatusCode = 503
};
options.AddPolicy("MyPolicy2", new RequestTimeoutPolicy {
Timeout = TimeSpan.FromMilliseconds(1000),
WriteTimeoutResponse = async (HttpContext context) => {
context.Response.ContentType = "text/plain";
await context.Response.WriteAsync("Timeout from MyPolicy2!");
}
});
});
app.MapGet("/usepolicy2", async (HttpContext context) => {
try
{
await Task.Delay(TimeSpan.FromSeconds(10), context.RequestAborted);
}
catch (TaskCanceledException)
{
throw;
}
return Results.Content("No timeout!", "text/plain");
}).WithRequestTimeout("MyPolicy2");
// Returns "Timeout from MyPolicy2!" due to WriteTimeoutResponse in MyPolicy2.
Désactiver les délais d’expiration
Pour désactiver tous les délais d’expiration, y compris le délai d’expiration global par défaut, utilisez l’attribut [DisableRequestTimeout] ou la DisableRequestTimeout méthode d’extension :
app.MapGet("/disablebyattr", [DisableRequestTimeout] async (HttpContext context) => {
try
{
await Task.Delay(TimeSpan.FromSeconds(10), context.RequestAborted);
}
catch
{
return Results.Content("Timeout!", "text/plain");
}
return Results.Content("No timeout!", "text/plain");
});
// Returns "No timeout!", ignores default timeout.
app.MapGet("/disablebyext", async (HttpContext context) => {
try
{
await Task.Delay(TimeSpan.FromSeconds(10), context.RequestAborted);
}
catch
{
return Results.Content("Timeout!", "text/plain");
}
return Results.Content("No timeout!", "text/plain");
}).DisableRequestTimeout();
// Returns "No timeout!", ignores default timeout.
Annuler un délai d’expiration
Pour annuler un délai d’expiration qui a déjà été démarré, utilisez la DisableTimeout() méthode sur IHttpRequestTimeoutFeature. Les délais d’expiration ne peuvent pas être annulés une fois qu’ils ont expiré.
app.MapGet("/canceltimeout", async (HttpContext context) => {
var timeoutFeature = context.Features.Get<IHttpRequestTimeoutFeature>();
timeoutFeature?.DisableTimeout();
try
{
await Task.Delay(TimeSpan.FromSeconds(10), context.RequestAborted);
}
catch (TaskCanceledException)
{
return Results.Content("Timeout!", "text/plain");
}
return Results.Content("No timeout!", "text/plain");
}).WithRequestTimeout(TimeSpan.FromSeconds(1));
// Returns "No timeout!" since the default timeout is not triggered.