使用 ASP.net 核心(API 控制器)处理基本控制器中的异常

Posted

技术标签:

【中文标题】使用 ASP.net 核心(API 控制器)处理基本控制器中的异常【英文标题】:Handling Exceptions in a Base Controller with ASP.net core (API controller) 【发布时间】:2018-03-30 12:28:41 【问题描述】:

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

[HttpPost]
public List<Foo> Post([FromBody]Bar model)

    if (model == null)
    
        throw new ArgumentNullException();
    

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

    return dto;

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

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

我希望以此为起点:

[HttpPost]
public StandardFoo Post([FromBody]Bar model)

    if (model == null)
    
        throw new ArgumentNullException();
    

    // business logic

    return new StandardFoo()Payload: dto;

模型验证或business logic 引发的异常会冒泡到某个逻辑,该逻辑返回一个新的StandardFoo,其属性包含异常详细信息。

【问题讨论】:

文档:docs.microsoft.com/en-us/aspnet/core/fundamentals/… 您关注的是错误的方法。您应该避免使用您正在尝试的异常方法的基本控制器以及控制器中的 try catch。控制器应尽可能精简,并将职责合并到另一个类中。这似乎是XY problem。 @Nkosi 能否提供一个简单、简洁的示例,说明如何在抛出异常时采用上述控制器并返回自定义响应? @Nkosi 更新了我正在寻找的清晰示例。在这里寻找实用的解决方案,而不是理论。 基本控制器在 MVC/WebApi 中通常不是一个好主意,因为它通过继承将 cross cutting concerns 紧密耦合到您的控制器。更好的方法是使用filters,这样您就可以共享功能,同时仍然可以在需要时轻松地在控制器或操作级别选择加入/退出。 【参考方案1】:

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

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

如果不是,我创建一个 ErrorResponse 并返回一个错误请求。

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

通过这种方式,它在具有需要验证的模型以及您想要在管道中的这一点执行的任何其他检查的所有端点之间变得统一。

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

   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());
        
    

【讨论】:

【参考方案2】:

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


相反,您需要将代码中的正常流和错误流分开,然后分别处理错误流。表明无法正常流程的主要方法之一是引发 .NET 异常(并使用它)。但是:

控制器操作应该只知道正常流。没有try-catch 逻辑等等。

对于输入验证,请使用 ActionFilter。您可能有所有控制器的全局过滤器或定义特定的每个操作。请参阅文档中的 Filters section。 ASP.NET Core 也允许Model Validation。

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

那么如何处理引发的异常呢?

使用 ASP.NET Core 提供的错误处理方法(如 ExceptionHandler 或 Exception Filters),它允许分析异常并相应地生成适当/不同的响应。以相关的 SO Error handling in ASP.NET Core 问题为例。文档中还有error-handling section。

【讨论】:

【参考方案3】:

如果您使用的是 .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

这可以将作为横切关注点的错误处理逻辑移除到一个专用组件中,从而使您的控制器保持精简并承担单一职责 - 最终使您的代码/应用程序更易于维护和健壮。

【讨论】:

以上是关于使用 ASP.net 核心(API 控制器)处理基本控制器中的异常的主要内容,如果未能解决你的问题,请参考以下文章

结合 Razor Pages 和 ApiControllers 的应用程序中的 Asp.net 核心异常处理

使用静态基类方案让 ASP.NET Core 实现遵循 HATEOAS Restful Web API

从 ASP.NET 核心中的类库加载和注册 API 控制器

ASP.NET 核心:NSwag 与 Swashbuckle

模型绑定不适用于 asp.net 核心 Web api 控制器操作方法中的 Stream 类型参数。(即使使用自定义流输入格式化程序)

如何在asp.net核心中从客户端调用web api方法?