如何使用ASP.NET Core使上游异常返回UnprocessableEntityResult



当一个请求进入我的ASP.NET Core API控制器,该控制器格式正确,但由于某种业务规则在违反时抛出异常而无法处理时,我希望返回一个422 HTTP响应,并在主体中包含错误文本。我希望这能在我的控制器上处理许多操作,而不需要向每个操作添加诸如try/catch块之类的代码。

我怎样才能做到这一点?

在应用程序中实现IAsyncExceptionFilter可能是最简单的——这可以在控制器操作中发现未处理的异常,并将其重写为您想要的形式,例如此处所需的422 HTTP响应。如果实现IAsyncExceptionFilter,您可以使用下面的代码(使用ASP.NET Core 3.1进行测试(将异常消息以纯文本形式返回给客户端:

public override async Task OnExceptionAsync(ExceptionContext context) {
if (!context.HttpContext.Response.HasStarted) {
var errorMessage = "Could not do that because of X reason."; // or you could use `context.Exception.Message` if it is secure in your application to do so
var responseBytes = Encoding.UTF8.GetBytes(errorMessage).AsMemory();
context.Result = new UnprocessableEntityResult();
context.HttpContext.Response.StatusCode = 422;
context.HttpContext.Response.ContentType = "text/plain;charset=UTF-8";
context.HttpContext.Response.ContentLength = responseBytes.Length;
await context.HttpContext.Response.BodyWriter.WriteAsync(responseBytes);
context.ExceptionHandled = true;
} else {
// if the response has already started, this can't be used.  You will have to figure
// out a different solution.
}
}

如果不使用IAsyncExceptionFilter,您仍然可以使用上面的大部分代码,那么需要在控制器的处理程序中的Response.HttpContext对象上设置相同的属性,然后返回UnprocessableEntityResult

请注意,正确设置ContentTypeContentLength标头将防止某些浏览器出现net::ERR_INCOMPLETE_CHUNKED_ENCODING错误。在这种情况下,ContentLength将是准确的,因为我们首先从Encoding.UTF8获得错误字符串的字节,并将ContentLength设置为这些字节的长度,而不仅仅是字符串长度。此外,ContentType报头包括charset=UTF-8限定符以去除任何歧义。

最新更新