簡體   English   中英

異常處理程序中間件未捕獲

[英]Exception handler middleware not catching

I'm developping a web API with ASP.NET Core and I'm trying to implement a custom error handling middleware so I can throw standard exceptions that can be converted into a JSON response with the appropriate HTTP Status code.

例如,如果我這樣做:

throw new NotFoundApiException("The object was not found");

我需要將其轉換為:

StatusCode: 404
ContentType: application/json
ResponseBody: {"error": "The object was not found"}

這是我的中間件

public class ErrorHandlingMiddleware
{
    private readonly RequestDelegate next;

    public ErrorHandlingMiddleware(RequestDelegate next)
    {
        this.next = next;
    }

    public async Task Invoke(HttpContext context)
    {
        try {
            await next(context);
        } catch (ApiException ex) {
            await HandleExceptionAsync(context, ex);
        }
    }

    private static Task HandleExceptionAsync(HttpContext context, ApiException exception)
    {
        var result = JsonConvert.SerializeObject(new { error = exception.Message });
        context.Response.ContentType = "application/json";
        context.Response.StatusCode = exception.httpStatusCode;

        return context.Response.WriteAsync(result);
    }
}

例外

public class ApiException : System.Exception
{
    private int _httpStatusCode = (int)HttpStatusCode.InternalServerError;
    public ApiException() { }
    public ApiException(string message): base(message) { }

    public int httpStatusCode {
        get { return this._httpStatusCode; }
    }
}
public class NotFoundApiException : ApiException
{
    private int _httpStatusCode = (int)HttpStatusCode.BadRequest;
    public NotFoundApiException() { }
    public NotFoundApiException(string message): base(message) { }
}

啟動

public void Configure(/*...*/)
{
    loggerFactory.AddConsole();
    app.UseMiddleware<ErrorHandlingMiddleware>();
    app.UseMvc();
}

Controller 動作

[HttpGet("object/{guid}")]
public WebMessage Get(Guid guid)
{
    throw new NotFoundApiException(string.Format("The object {0} was not found", guid));
//...

我可以看到請求進入了我注冊的中間件,但異常沒有被捕獲,只是像往常一樣簡單地拋出

我懷疑是競態條件或類似情況,實際上我對它們的異步函數不太了解。

有人知道為什么我的異常沒有被捕獲嗎?


編輯通過使用 VisualStudio 繼續執行,我可以看到預期的行為:我終於得到了回應。
似乎異常並沒有真正被中間件捕獲,而是在之后以某種方式處理。

我對這個問題的解決方案是刪除app.UseDeveloperExceptionPage(); Startup.cs

您也可以嘗試Exception filters

(當然,過濾器不像錯誤處理中間件那樣靈活,這在一般情況下更好,但是 - 至少對我來說 - 過濾器工作正常,沒有任何問題)

這就是我正在使用的:

public class ExceptionGlobalFilter : ExceptionFilterAttribute
{
    private readonly ILogger logger;

    public ExceptionGlobalFilter(ILoggerFactory lf)
    {
        logger = lf.CreateLogger("ExceptionGlobalFilter");
    }


    public override void OnException(ExceptionContext context)
    {
        var customObject = new CustomObject(context.Exception);

        //TODO: Add logs
        if (context.Exception is BadRequestException)
        {
            context.Result = new BadRequestObjectResult(customObject);
        }
        else if (context.Exception is NotFoundException)
        {
            context.Result = new NotFoundObjectResult(customObject);
        }
        else
        {
            context.Result = new OkObjectResult(customObject);
        }

        base.OnException(context);
    }


    public override async Task OnExceptionAsync(ExceptionContext context)
    {
        await base.OnExceptionAsync(context);
        return;
    }
}


Startup.cs

services.AddMvc(config =>
{
    config.Filters.Add(typeof(ExceptionGlobalFilter));
});


更多信息:

就我而言,我發現app.UseMiddleware<ExceptionHandlingMiddleware>(); 應該在Configure()方法的頂部。

在我的情況下app.UseDeveloperExceptionPage(); 是寫在Startup之后的異常處理中間件。 修復只是將異常處理程序中間件移到它之后。

@Pierre,在使用中間件作為全局異常處理程序時,我在這里遇到了同樣的問題。 該問題是由於我錯誤地編寫了“async void”方法引起的,我在名為“NewException”的方法中拋出了一個異常:

[Route("api/[controller]")]
[ApiController]
public class ValuesController : ControllerBase
{
    // GET api/values
    [HttpGet]
    public async Task<IActionResult> Get()
    {
        NewException();
        return Ok("<h1>Hi, Welcome!</h1>");
    }

    private async void NewException()
    {
        throw new InvalidOperationException("WTF");
    }

異常 [InvalidOperationException("WTF")] 將不會被中間件捕獲,如果我將代碼片段更改為:

[Route("api/[controller]")]
[ApiController]
public class ValuesController : ControllerBase
{
    // GET api/values
    [HttpGet]
    public async Task<IActionResult> Get()
    {
        await NewException();
        return Ok("<h1>Hi, Welcome!</h1>");
    }

    private async Task NewException()
    {
        throw new InvalidOperationException("WTF");
    }

異常中間件將捕獲它。 希望這有幫助。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM