[英]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.