admin管理员组

文章数量:1431497

I'm trying to implement a generic timeout for my requests in C#. I'm aware of the request timeout middleware, but it can't be instructed (as the middleware is handling the exception) to pass the exception so that our normal problem middleware (wrapping it in ProblemDetails) can handle it. So I rolled a simple one to start with:

public class CancelInTimeMiddleware : IMiddleware
{
    // Better understanding of why we can't stop all requests very easiliy: 
    public async Task InvokeAsync(HttpContext context, RequestDelegate next)
    {
        var originalCt = context.RequestAborted;
        using (var timoutTS = CancellationTokenSource.CreateLinkedTokenSource(originalCt))
        {
            timoutTS.CancelAfter(10000);       // Always cancel after 10 seconds
            context.RequestAborted = timoutTS.Token;
            await next(context);
        }
    }
}

And a simple endpoint:

    public static async Task<IResult> GetTimer(int delaySeconds, CancellationToken cancellationToken)
    {
      logger.LogInformation("Entering the wait!");
      await Task.Delay(delaySeconds * 1000, cancellationToken);

        //catch (TaskCanceledException) -> I also want to handle cases where this is fotten.

        return Results.Json(new { Message = "Waiting is done" });
    }

So I added this simple IExceptionHandler (thank you SO):

class SimpleExceptionHandler : IExceptionHandler
{
    public async ValueTask<bool> TryHandleAsync(
        HttpContext httpContext,
        Exception exception,
        CancellationToken cancellationToken)
    {
        // Your response object
        var error = new { message = exception.Message };
        await httpContext.Response.WriteAsJsonAsync(error, cancellationToken);
        return true;
    }
}

And registered it like this:

builder.Services.AddProblemDetails();
builder.Services.AddExceptionHandler<SimpleExceptionHandler>();
builder.Services.AddSingleton<CancelInTimeMiddleware>();

var app = builder.Build();
app.UseExceptionHandler(_ => { });
app.UseMiddleware<CancelInTimeMiddleware>();
app.MapGet("wait/{delaySeconds:int}", TestEndPointsImplementations.GetTimer);
app.Run();

It does work for other exceptions that I throw: but not when the cancellation is done. Is this because the request pipeline stops when the CancellationToken is triggered?

本文标签: cHandling TaskCanceledException by IExceptionHandlerStack Overflow