在ASP.NET Core MVC中捕获异常

时间:2018-09-09 02:41:12

标签: c# asp.net-core asp.net-core-webapi

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

我添加了以下内容:

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。

我在这里想念什么?

1 个答案:

答案 0 :(得分:2)

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

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

  1. 更新您的OnExceptionAsync函数以使用ActionExecutedContext代替ActionExecutingContext
  2. 将呼叫更新为OnExceptionAsync,而不是executed,而是提供context。在这里的同时,您还可以将方法参数折叠为 just 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;
    }
}