异常处理程序中间件未捕获



我正在使用 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继续执行,我可以看到预期的行为:我终于得到了回应。
似乎异常并没有真正被中间件捕获,而是在之后以某种方式处理。

我对这个问题的解决方案是删除app.UseDeveloperExceptionPage();Startup.cs

就我而言,我发现app.UseMiddleware<ExceptionHandlingMiddleware>();应该位于Configure()方法的顶部。

您也可以尝试异常过滤器。

(当然,过滤器不像错误处理中间件那样灵活,这在一般情况下更好,但是 - 至少对我来说 - 过滤器工作正常,没有任何问题)

这就是我正在使用的:

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


更多信息:

  • ASP.NET 核心中的错误处理简介
  • 异常筛选器
  • 过滤 器
  • MVC 问题 #5594
  • ExceptionHandlerMiddleware.cs

就我而言,app.UseDeveloperExceptionPage();是在异常处理程序中间件之后的Startup中编写的。修复只需将异常处理程序中间件移动到它之后即可。

@Pierre,在使用中间件作为全局异常处理程序时,我在这里遇到了同样的问题。该问题是由于我错误地编写了"异步 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");
}

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

最新更新