Share via


ASP.NET Core'da zaman aşımlarını isteme ara yazılımı

Tarafından Tom Dykstra

Uygulamalar isteklere seçmeli olarak zaman aşımı sınırları uygulayabilir. ASP.NET Çekirdek sunucuları, istek işleme süreleri senaryoya göre büyük ölçüde değiştiğinden bunu varsayılan olarak yapmaz. Örneğin, WebSockets, statik dosyalar ve pahalı API'lerin çağrılması farklı bir zaman aşımı sınırı gerektirir. Bu nedenle ASP.NET Core, hem uç nokta başına zaman aşımlarını hem de genel zaman aşımını yapılandıran ara yazılım sağlar.

Zaman aşımı sınırına basıldığında, içinde CancellationTokenHttpContext.RequestAbortedIsCancellationRequested olarak trueayarlanır. Abort() istekte otomatik olarak çağrılmaz, bu nedenle uygulama yine de başarılı veya başarısız bir yanıt üretebilir. Uygulama özel durumu işlemez ve bir yanıt üretirse varsayılan davranış 504 durum kodunu döndürmektir.

Bu makalede zaman aşımı ara yazılımının nasıl yapılandırılır açıklanmaktadır. Zaman aşımı ara yazılımı her tür ASP.NET Core uygulamasında kullanılabilir: Minimal API, Denetleyicili Web API'leri, MVC ve Razor Sayfalar. Örnek uygulama En Az API'dir, ancak her zaman aşımı özelliği diğer uygulama türlerinde de desteklenir.

İstek zaman aşımları ad alanındadır Microsoft.AspNetCore.Http.Timeouts .

Not: Bir uygulama hata ayıklama modunda çalışırken zaman aşımı ara yazılımı tetiklemez. Bu davranış, zaman aşımlarıyla aynıdırKestrel. Zaman aşımlarını test etmek için, hata ayıklayıcı eklenmeden uygulamayı çalıştırın.

Ara yazılımı uygulamaya ekleme

çağrısı AddRequestTimeoutsyaparak istek zaman aşımları ara yazılımını hizmet koleksiyonuna ekleyin.

ara yazılımı çağrısı UseRequestTimeoutsyaparak istek işleme işlem hattına ekleyin.

Dekont

  • açıkça çağıran UseRoutinguygulamalarda, UseRequestTimeouts 'den sonra UseRoutingçağrılmalıdır.

Ara yazılımı uygulamaya eklemek otomatik olarak zaman aşımlarını tetiklemeye başlamaz. Zaman aşımı sınırlarının açıkça yapılandırılması gerekir.

Bir uç nokta veya sayfa yapılandırma

En düşük API uygulamaları için, aşağıdaki örnekte gösterildiği gibi çağrısı WithRequestTimeoutyaparak veya özniteliğini uygulayarak [RequestTimeout] bir uç noktayı zaman aşımına olacak şekilde yapılandırın:

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();

Denetleyicili uygulamalar için özniteliğini [RequestTimeout] eylem yöntemine veya denetleyici sınıfına uygulayın. Pages uygulamaları için Razor özniteliğini sayfa sınıfına Razor uygulayın.

Birden çok uç nokta veya sayfa yapılandırma

Birden çok uç noktaya uygulanan zaman aşımı yapılandırmasını belirtmek için adlandırılmış ilkeler oluşturun. çağrısı AddPolicyyaparak bir ilke ekleyin:

builder.Services.AddRequestTimeouts(options => {
    options.DefaultPolicy =
        new RequestTimeoutPolicy { Timeout = TimeSpan.FromMilliseconds(1500) };
    options.AddPolicy("MyPolicy", TimeSpan.FromSeconds(2));
});

İlke adına göre bir uç nokta için zaman aşımı belirtilebilir:

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!"

Özniteliği, [RequestTimeout] adlandırılmış bir ilke belirtmek için de kullanılabilir.

Genel varsayılan zaman aşımı ilkesini ayarlama

Genel varsayılan zaman aşımı yapılandırması için bir ilke belirtin:

builder.Services.AddRequestTimeouts(options => {
    options.DefaultPolicy =
        new RequestTimeoutPolicy { Timeout = TimeSpan.FromMilliseconds(1500) };
    options.AddPolicy("MyPolicy", TimeSpan.FromSeconds(2));
});

Varsayılan zaman aşımı, zaman aşımı belirtilmemiş uç noktalar için geçerlidir. Aşağıdaki uç nokta kodu, uzantı yöntemini çağırmasa veya özniteliğini uygulamasa da zaman aşımını denetler. Genel zaman aşımı yapılandırması geçerli olduğundan kod zaman aşımını denetler:

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.

İlkedeki durum kodunu belirtme

sınıfı, RequestTimeoutPolicy zaman aşımı tetiklendiğinde durum kodunu otomatik olarak ayarlayabilen bir özelliğe sahiptir.

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.

İlkede temsilci kullanma

sınıfı RequestTimeoutPolicy , zaman aşımı tetiklendiğinde yanıtı özelleştirmek için kullanılabilecek bir özelliğe sahiptir WriteTimeoutResponse .

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.

Zaman aşımlarını devre dışı bırakma

Varsayılan genel zaman aşımı dahil olmak üzere tüm zaman aşımlarını devre dışı bırakmak için özniteliğini [DisableRequestTimeout] veya DisableRequestTimeout uzantı yöntemini kullanın:

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.

Zaman aşımını iptal etme

Zaten başlatılmış bir zaman aşımını iptal etmek için üzerinde IHttpRequestTimeoutFeatureyöntemini kullanınDisableTimeout(). Zaman aşımları süresi dolduktan sonra iptal edilemez.

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.

Ayrıca bkz.