简体   繁体   English

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

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

Many of our current controllers look like this: 我们当前的许多控制器如下所示:

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

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

    return dto;
}

A lot of code is being repeated here though. 不过,这里重复了很多代码。 What I'd like to do is implement a base controller that handles exceptions so I can return a standardized response with fields like Payload , Success , Error , etc. 我想做的是实现一个处理异常的基本控制器,这样我就可以返回带有PayloadSuccessError等字段的标准化响应

Prior to .net core this was possible by providing an override of OnException however this doesn't appear to work with a .net core api controller. 在.net core之前,可以通过提供OnException的覆盖来实现,但是这似乎不适用于.net core api控制器。 How do I go about consolidating this exception logic to return a custom response when things go awry in my controller bodies? 当控制器主体出现问题时,如何合并该异常逻辑以返回自定义响应?

I'd like this, as a starting point: 我想以此为起点:

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

    // business logic

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

Where exceptions thrown by model validation or business logic bubble up to some piece of logic that returns a new StandardFoo with a property containing the exception details. 由模型验证或business logic引发的异常会上升到某种business logic上,这些逻辑返回一个新的StandardFoo ,其StandardFoo属性包含异常详细信息。

If shortly, you should not catch and process exceptions in your controllers. 如果很快,您就不应在控制器中捕获和处理异常。


Instead, you need to separate normal and error flows in your code and then process error flow separately. 相反,您需要在代码中分离正常流和错误流,然后分别处理错误流。 One of the main approaches to indicate that normal flow is not possible is to raise the .NET Exceptions (and you use it). 指示无法正常进行的主要方法之一是引发.NET异常(并且您可以使用它)。 But: 但:

  • Controllers actions should be aware only of normal flow. 控制器的动作应仅注意正常流程。 No try-catch logic and so on. 没有try-catch逻辑等等。
  • For input validation use ActionFilter . 对于输入验证,请使用ActionFilter You may have global filters for all controllers or define specific per action. 您可能具有所有控制器的全局过滤器,或为每个操作定义特定的过滤器。 See Filters section in documentation. 请参阅文档中的“ 过滤器”部分 ASP.NET Core allows also do Model Validation . ASP.NET Core也允许进行模型验证

  • During controller action execution you should raise exceptions as soon as possible and stop further pipeline execution. 在执行控制器动作期间,应尽快引发异常并停止进一步的管道执行。 And yes, the Exception may be raised on any of the levels (action level, Service/Business layer, DA layer, etc). 是的,可以在任何级别(操作级别,服务/业务层,DA层等)上引发异常。

How to handle the raised exception then? 那么如何处理引发的异常呢?

  • use provided by ASP.NET Core error handling approaches (like ExceptionHandler, or Exception Filters), it allows to analyze exceptions and generate appropriate/different responses accordingly. 由于使用了ASP.NET Core错误处理方法(例如ExceptionHandler或Exception Filters)所提供的功能,因此它可以分析异常并相应地生成适当/不同的响应。 Look into related SO Error handling in ASP.NET Core question for the example. 查看该示例中ASP.NET Core问题中的相关SO 错误处理 There is also the error-handling section in documentation. 文档中还有错误处理部分

I would recommend creating a custom action filter. 我建议创建一个自定义操作过滤器。 This can be wrapped around every incoming request in the WebApiConfig Register method(See below). 这可以包装在WebApiConfig Register方法中的每个传入请求周围(见下文)。

In my example, I am checking that the model state is valid. 在我的示例中,我正在检查模型状态是否有效。

If it's not, I create an ErrorResponse and send back a Bad Request. 如果不是,则创建一个ErrorResponse并发送回一个错误请求。

You don't have to simply send back the model state like in the example below, you could return anything you actually want. 您不必像下面的示例那样简单地发回模型状态,您可以返回您实际想要的任何内容。

This way it becomes uniform across all endpoints that have a model that needs to be validated as well as any other checks you want to do at this point in the pipeline. 这样,它就可以在具有需要验证模型的所有端点以及您要在管道中进行的任何其他检查中变得一致。

Note: Because we are registering this attribute globally we dont then have to declare it anywhere else, from this point on, all incoming traffic be inspected by this 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());
        }
    }

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM