ErrorHandling Middleware catch 永远不会被捕获

ErrorHandling Middleware catch is never caught

我有这个 ErrorHandlingMiddleware,看起来像这样:

public class ErrorHandlingMiddleware
{
    private readonly RequestDelegate _next;
    public ErrorHandlingMiddleware(RequestDelegate next)
    {
        this._next = next;
    }

    public async Task Invoke(HttpContext context /* other dependencies */)
    {
        try
        {
            await _next(context);
        }
        catch (Exception ex)
        {
            await HandleExceptionAsync(context, ex);
        }
    }

    private static Task HandleExceptionAsync(HttpContext context, Exception ex)
    {
        var statusCode = (int)HttpStatusCode.InternalServerError;

        if (ex is NotFoundError) statusCode = (int)HttpStatusCode.NotFound;
        //else if (ex is MyUnauthorizedException) code = HttpStatusCode.Unauthorized;
        //else if (ex is MyException) code = HttpStatusCode.BadRequest;

        var error = new AttemptError(statusCode, ex.Message, ex);

        context.Response.ContentType = "application/json";
        context.Response.StatusCode = statusCode;

        return context.Response.WriteAsync(error.ToString());
    }
}

我已将此添加到我的 Startup class:

public void Configure(IApplicationBuilder app)
{
    app.UseMiddleware<ErrorHandlingMiddleware>();
    app.SeedIdentityServerDatabase();
    app.UseDeveloperExceptionPage();

    app.UseIdentityServer();
    app.UseSwagger();
    app.UseSwaggerUI(c =>
    {
        c.SwaggerEndpoint("/swagger/v1/swagger.json", "r3plica Identity Server v1");
        c.OAuthClientId("swagger");
        c.OAuthAppName("Swagger Api UI");
    });
    app.UseMvc();
}

我希望如果我在我的应用程序中的任何地方抛出异常,它会被捕获并执行以下行:

await HandleExceptionAsync(context, ex);

所以,我设置了一个测试:

throw new Exception();

这是在我的控制器中抛出的。当我 运行 我的应用程序然后调用抛出该异常的端点时,它确实到达了我的 ErrorHandlingMiddlewareInvoke 方法,但它没有捕获异常,它只是去 await _next(context).....

有谁知道我做错了什么吗?

如果您在 Startup 中的 app.UseDeveloperExceptionPage(); 之后调用使用它,您的中间件将会工作。

Handle errors in ASP.NET Core

Place the call to UseDeveloperExceptionPage before any middleware that you want to catch exceptions.

我通过创建过滤器解决了这个问题:

public class HttpResponseExceptionFilter : IActionFilter, IOrderedFilter
{
    public int Order { get; set; } = int.MaxValue - 10;

    public void OnActionExecuting(ActionExecutingContext context) { }

    public void OnActionExecuted(ActionExecutedContext context)
    {
        if (context.Exception == null) return;

        var attempt = Attempt<string>.Fail(context.Exception);

        if (context.Exception is AttemptException exception)
        {
            context.Result = new ObjectResult(attempt)
            {
                StatusCode = exception.StatusCode,
            };
        }
        else
        {
            context.Result = new ObjectResult(attempt)
            {
                StatusCode = (int)HttpStatusCode.InternalServerError,
            };
        }

        context.ExceptionHandled = true;
    }
}

然后这样注册:

services.AddControllers(options => options.Filters.Add(new HttpResponseExceptionFilter()));