Nota
L'accesso a questa pagina richiede l'autorizzazione. È possibile provare ad accedere o modificare le directory.
L'accesso a questa pagina richiede l'autorizzazione. È possibile provare a modificare le directory.
Di Tom Dykstra
Le app possono applicare limiti di timeout in modo selettivo alle richieste. ASP.NET i server Core non eseguono questa operazione per impostazione predefinita poiché i tempi di elaborazione delle richieste variano notevolmente in base a uno scenario. Ad esempio, WebSocket, file statici e chiamate api costose richiedono un limite di timeout diverso. Quindi ASP.NET Core fornisce middleware che configura i timeout per endpoint e un timeout globale.
Quando viene raggiunto un limite di timeout, in CancellationTokenHttpContext.RequestAborted è IsCancellationRequested impostato su true.
Abort() non viene chiamato automaticamente sulla richiesta, quindi l'applicazione può comunque produrre una risposta riuscita o non riuscita. Il comportamento predefinito se l'app non gestisce l'eccezione e genera una risposta consiste nel restituire il codice di stato 504.
Questo articolo illustra come configurare il middleware di timeout. Il middleware di timeout può essere usato in tutti i tipi di app Core di ASP.NET: API minima, API Web con controller, MVC e Razor Pagine. L'app di esempio è un'API minima, ma ogni funzionalità di timeout illustrata è supportata anche negli altri tipi di app.
I timeout delle richieste si trovano nel Microsoft.AspNetCore.Http.Timeouts spazio dei nomi.
Nota: Quando un'app è in esecuzione in modalità di debug, il middleware di timeout non viene attivato. Questo comportamento è uguale a quello per Kestrel i timeout. Per testare i timeout, eseguire l'app senza il debugger collegato.
Aggiungere il middleware all'app
Aggiungere il middleware per il timeout delle richieste alla raccolta di servizi chiamando AddRequestTimeouts.
Aggiungere il middleware alla pipeline di elaborazione delle richieste chiamando UseRequestTimeouts.
Annotazioni
- Nelle app che chiamano UseRoutingin modo esplicito ,
UseRequestTimeoutsdevono essere chiamate dopoUseRouting.
L'aggiunta del middleware all'app non avvia automaticamente i timeout. I limiti di timeout devono essere configurati in modo esplicito.
Configurare un endpoint o una pagina
Per le app API minime, configurare un endpoint per il timeout chiamando WithRequestTimeout o applicando l'attributo [RequestTimeout], come illustrato nell'esempio seguente.
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();
Per le app con controller, applicare l'attributo [RequestTimeout] al metodo di azione o alla classe controller. Per Razor le app Pages, applicare l'attributo alla Razor classe page.
Configurare più endpoint o pagine
Creare politiche denominate per specificare la configurazione di timeout applicabile a più endpoint. Aggiungere un criterio chiamando AddPolicy:
builder.Services.AddRequestTimeouts(options => {
options.DefaultPolicy =
new RequestTimeoutPolicy { Timeout = TimeSpan.FromMilliseconds(1500) };
options.AddPolicy("MyPolicy", TimeSpan.FromSeconds(2));
});
È possibile specificare un timeout per un endpoint in base al nome del criterio:
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'attributo [RequestTimeout] può essere usato anche per specificare un criterio denominato.
Impostare la politica di timeout predefinita globale
Specificare un criterio per la configurazione di timeout predefinita globale:
builder.Services.AddRequestTimeouts(options => {
options.DefaultPolicy =
new RequestTimeoutPolicy { Timeout = TimeSpan.FromMilliseconds(1500) };
options.AddPolicy("MyPolicy", TimeSpan.FromSeconds(2));
});
Il timeout predefinito si applica agli endpoint che non hanno un timeout specificato. Il codice endpoint seguente verifica la presenza di un timeout anche se non chiama il metodo di estensione o applica l'attributo. Si applica la configurazione globale del timeout, quindi il codice verifica la presenza di un timeout:
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.
Specificare il codice di stato in una politica
La RequestTimeoutPolicy classe ha una proprietà che può impostare automaticamente il codice di stato quando viene attivato un timeout.
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.
Usare un delegato in una politica
La RequestTimeoutPolicy classe ha una WriteTimeoutResponse proprietà che può essere usata per personalizzare la risposta quando viene attivato un timeout.
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.
Disabilitare i timeout
Per disabilitare tutti i timeout, incluso il timeout globale predefinito, usare l'attributo [DisableRequestTimeout] o il metodo di DisableRequestTimeout estensione:
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.
Annullare un timeout
Per annullare un timeout già avviato, usare il DisableTimeout() metodo in IHttpRequestTimeoutFeature. I timeout non possono essere annullati dopo la scadenza.
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.