在核心 MVC ASP.NET 捕获异常



我已经看到了多种在 MVC Core 中捕获异常的方法 ASP.NET 但我需要了解为什么我所做的没有按预期工作。

我添加了以下内容:

public abstract class GenericActionFilter : ActionFilterAttribute
{
protected readonly ILog Logger = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);

public override async Task OnActionExecutionAsync(ActionExecutingContext context, ActionExecutionDelegate next)
{
if (await OnBeforeActionExecutionAsync(context))
{
var executed = await next();
if (executed.Exception != null && !executed.ExceptionHandled)
{
await OnExceptionAsync(context, executed.Exception);
}
else
{
await OnAfterActionExecutionAsync(context);
}
}
}
public virtual Task<bool> OnBeforeActionExecutionAsync(ActionExecutingContext context)
{
return Task.FromResult(true);
}
public virtual Task OnAfterActionExecutionAsync(ActionExecutingContext context)
{
return Task.CompletedTask;
}
public virtual Task OnExceptionAsync(ActionExecutingContext context, Exception ex)
{
return Task.CompletedTask;
}
}

并像这样使用它:

public class ExceptionFilter : GenericActionFilter
{
public IntegrationScenarioSettings Settings { get; set; }

public override Task OnExceptionAsync(ActionExecutingContext context, Exception ex)
{
context.Result = new ContentResult
{
Content = Settings.ApiExecutionExceptionMessage,
StatusCode = (int)HttpStatusCode.ServiceUnavailable
};
//outputs to endpoint.log
Logger.Error(ex);
return Task.CompletedTask;
}
}

操作中的底层代码抛出异常,而不是看到 503,我仍然是 500。

我在这里错过了什么?

为了通知 ASP.NET Core MVC 管道你已处理异常,您需要将ActionExecutedContext.ExceptionHandled设置为true。由于所显示的代码中没有此信息,因此 ASP.NET Core MVC 管道使用自己的错误处理逻辑将(它认为是(未处理的异常转换为 500 响应。

现在 - 此属性存在于ActionExecutedContext上,而不是ActionExecutingContext(您在代码中使用(。这是有道理的,因为ActionExecutingContext表示操作运行之前的状态,ActionExecutedContext表示操作运行的状态。这意味着您将需要以下一组更改:

  1. 更新您的OnExceptionAsync函数以采用ActionExecutedContext而不是ActionExecutingContext
  2. 将调用更新为OnExceptionAsync,提供executed而不是context。当您在这里时,您还可以将方法参数折叠为executed(我将在下面的代码中显示这一点(。
  3. 一旦你处理了异常,就context.ExceptionHandled设置为true。 :)

我从您的问题中获取了代码,删除了一些与问题无关的代码并应用了这些更改,我用上面的相应数字调用了这些更改:

public abstract class GenericActionFilter : ActionFilterAttribute
{
public override async Task OnActionExecutionAsync(ActionExecutingContext context,
ActionExecutionDelegate next)
{
if (await OnBeforeActionExecutionAsync(context))
{
var executed = await next();
if (executed.Exception != null && !executed.ExceptionHandled)
{
await OnExceptionAsync(executed); // #2.
}
else
{
// NOTE: You might want to use executed here too.
await OnAfterActionExecutionAsync(context);
}
}
}
// ...
public virtual Task OnExceptionAsync(ActionExecutedContext context) // #1.
{
return Task.CompletedTask;
}
}

public class ExceptionFilter : GenericActionFilter
{    
public override Task OnExceptionAsync(ActionExecutedContext context) // #1, #2.
{
Logger.Error(context.Exception); // #2 (single parameter).
context.Result = new ContentResult { ... };
context.ExceptionHandled = true; // #3.
return Task.CompletedTask;
}
}

最新更新