我正在开发 WebAPI 并希望捕获我所有的 ApiException 自定义异常并显示 WebAPI 友好的响应。 ApiException 异常可以从 Action
或 Filter
中抛出,例如 IAuthorizationFilter
或 ActionFilterAttribute
。
首先我尝试使用 IExceptionFilter
但后来我发现 IExceptionFilter
只处理从 Actions 而不是从其他 Filters 抛出的异常。
public class ApiExceptionFilter : IExceptionFilter
{
public void OnException(ExceptionContext context)
{
var exception = context.Exception;
if (exception is not ApiException responseException)
{
responseException = new ApiException(ResponseMessageType.UnhandledException);
}
context.Result = new ObjectResult(new ResultMessageDto(responseException))
{
StatusCode = responseException.HttpStatusCode
};
}
}
我发现很多人建议使用的第二种方法是中间件,但这不是 WebAPI 设计的正确方法。
public class ErrorHandlerMiddleware
{
private readonly RequestDelegate _next;
public ErrorHandlerMiddleware(RequestDelegate next)
{
_next = next;
}
public async Task Invoke(HttpContext context)
{
try
{
await _next(context);
}
catch (Exception exception)
{
var response = context.Response;
response.ContentType = "application/json";
if (exception is not ApiException responseException)
{
responseException = new ApiException(ResponseMessageType.UnhandledException);
}
response.StatusCode = responseException.HttpStatusCode;
await response.WriteAsJsonAsync(new ResultMessageDto(responseException), new JsonSerializerOptions()
{
DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull,
PropertyNamingPolicy = null
});
}
}
}
中间件异常处理会跳过 WebAPI MVC OutputFormaters
并仅以 JSON 或开发人员设置的内容进行响应。这个解决方案在设计上很糟糕,因为不尊重 Accept
header 。
如何在 Actions
和 Filters
中处理 Exceptions
而无需 leaving MVC scope
?
最佳答案
我觉得最好在中间件中处理,这里是一个示例代码。我使用的是 Json,但在这里,您可以使用任何输出格式化程序(甚至是自定义的)。
public async Task InvokeAsync(HttpContext context, RequestDelegate next)
{
try
{
await next(context);
}
catch (Exception ex)
{
await HandleExceptionAsync(context, ex);
}
}
private async Task HandleExceptionAsync(HttpContext context, Exception exception)
{
int statusCode = StatusCodes.Status500InternalServerError;
string exceptionType, exceptionDetail;
context.Response.ContentType = "application/json";
switch (exception)
{
case ArgumentNullException:
exceptionType = "Argument Null Exception";
exceptionDetail = exception.Message;
break;
case ApiException:
exceptionType = "API Exception";
exceptionDetail = exception.Message;
break;
default:
exceptionType = "Unhandled"
exceptionDetail = "Something went wrong";
break;
}
var problemDetails = new Microsoft.AspNetCore.Mvc.ProblemDetails
{
Status = statusCode,
Type = exceptionType,
Title = "An error has occurred within the PromComm Application",
Detail = exceptionDetail,
Instance = context.Request.Path
};
// You can use any formatter here even with custom messages
var problemDetailsJson = System.Text.Json.JsonSerializer.Serialize(problemDetails);
context.Response.StatusCode = statusCode;
await context.Response.WriteAsync(problemDetailsJson);
}
关于c# - 在不跳过 OutputFormatter 的情况下捕获异常并使用自定义消息进行响应,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/73812033/