在具有 ASP.net 核心的基础控制器中处理异常(API 控制器)

Handling Exceptions in a Base Controller with ASP.net core (API controller)

我们当前的许多控制器看起来像这样:

[HttpPost]
public List<Foo> Post([FromBody]Bar model)
{
    if (model == null)
    {
        throw new ArgumentNullException();
    }

    try
    {
        // business logic
    }
    catch (Exception ex)
    {
        // logging
    }

    return dto;
}

这里重复了很多代码。我想做的是实现一个处理异常的基本控制器,这样我就可以 return 一个 标准化响应 ,其中包含 PayloadSuccess 等字段, Error, 等等

在 .net 核心之前,这可以通过提供 OnException 的覆盖来实现,但这似乎不适用于 .net 核心 api 控制器。当我的控制器主体出现问题时,如何将此异常逻辑整合到 return 自定义响应?

我喜欢这个,作为起点:

[HttpPost]
public StandardFoo Post([FromBody]Bar model)
{
    if (model == null)
    {
        throw new ArgumentNullException();
    }

    // business logic

    return new StandardFoo(){Payload: dto};
}

模型验证抛出的异常或 business logic 冒出一些逻辑,return 是一个新的 StandardFoo,属性 包含异常详细信息。

我建议创建自定义操作过滤器。这可以围绕 WebApiConfig 注册方法中的每个传入请求进行包装(见下文)。

在我的示例中,我正在检查模型状态是否有效。

如果不是,我创建一个 ErrorResponse 并发回一个 Bad Request。

您不必像下面的示例那样简单地发回模型状态,您可以return任何您真正想要的东西。

这样一来,所有具有需要验证的模型的端点以及您希望在管道中此时执行的任何其他检查都变得统一。

注意:因为我们正在全局注册此属性,所以我们不必在其他任何地方声明它,从现在开始,所有传入流量都将由此 class 检查。

   public class ValidateModelAttribute : ActionFilterAttribute
        {
            public override void OnActionExecuting(HttpActionContext actionContext)
            {

                if (!actionContext.ModelState.IsValid)
                {
                    actionContext.Response = actionContext.Request.CreateErrorResponse(HttpStatusCode.BadRequest, actionContext.ModelState);
                }
            }

            public override bool AllowMultiple
            {
                get { return false; }
            }
        }



public static class WebApiConfig
    {
        public static void Register(HttpConfiguration config)
        {
            // Web API configuration and services
            config.Filters.Add(new ValidateModelAttribute());
        }
    }

如果很快,您不应该在控制器中捕获和处理异常。


相反,您需要在代码中分离正常流和错误流,然后分别处理错误流。指示正常流程不可能的主要方法之一是引发 .NET 异常(并且您使用它)。但是:

  • 控制器操作应该只知道正常流。没有try-catch逻辑等等。
  • 输入验证使用 ActionFilter。您可以为所有控制器设置全局过滤器或为每个操作定义特定的过滤器。见 Filters section in documentation. ASP.NET Core allows also do Model Validation.

  • 在控制器操作执行期间,您应该尽快引发异常并停止进一步的管道执行。是的,可以在任何级别(操作级别、Service/Business 层、DA 层等)上引发异常。

那么如何处理抛出的异常?

  • 使用由 ASP.NET 提供的核心错误处理方法(如 ExceptionHandler 或异常过滤器),它允许分析异常并相应地生成 appropriate/different 响应。查看文档中的相关 SO question for the example. There is also the error-handling section

如果您使用的是 .Net Core,处理错误的一种好方法是使用异常处理中间件。

有关详细信息,请参阅这些文章:

https://code-maze.com/global-error-handling-aspnetcore/

https://docs.microsoft.com/en-us/aspnet/core/fundamentals/error-handling?view=aspnetcore-5.0

这可以将错误处理逻辑(这是一个横切关注点)移除到一个专用组件中,从而使您的控制器保持精简并承担单一责任 - 最终使您的 code/application 更易于维护和健壮.