异常处理程序中间件没有捕获

时间:2017-06-20 15:34:44

标签: c# asp.net asp.net-core

我正在使用ASP.NET Core开发Web API,并且我正在尝试实现自定义错误处理中间件,因此我可以抛出可以使用适当的HTTP状态代码转换为JSON响应的标准异常。

例如,如果我这样做:

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

控制器操作

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

我可以看到请求进入我的注册中间件,但是异常没有被捕获并且像往常一样被抛出

我怀疑是竞争条件或类似情况,我实际上并不太了解它们的异步功能。

有人知道为什么我的异常没有被捕获吗?

编辑通过继续使用VisualStudio执行,我可以看到预期的行为:我终于得到了我的回复。
看起来像中间件并没有真正捕获异常,但后来以某种方式进行了处理。

4 个答案:

答案 0 :(得分:4)

我解决此问题的方法是删除app.UseDeveloperExceptionPage();

中的Startup.cs

答案 1 :(得分:2)

您也可以尝试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));
});


更多信息:

答案 2 :(得分:1)

以我为例,我发现app.UseMiddleware<ExceptionHandlingMiddleware>();应该在Configure()方法的顶部。

答案 3 :(得分:0)

@Pierre,使用中间件作为全局异常处理程序时,我在这里遇到了同样的问题。这个问题是由于我写一个“异步无效”方法的错误引起的,我在名为“ 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");
    }

异常中间件将捕获它。希望有帮助。