442  
查询码:00000092
ABP异常处理小技巧
作者: 李晶晶 于 2020年06月04日 发布在分类 / 人防组 / 人防后端 下,并于 2020年06月04日 编辑
abp 异常

简介

Abp 框架本身针对内部抛出异常进行了统一拦截,并且针对不同的异常也会采取不同的处理策略。在 Abp 当中主要提供了以下几种异常类型:

异常类型 描述
AbpException
Abp 框架定义的基本异常类型,Abp 所有内部定义的异常类型都继承自本类
AbpInitializationException
Abp 框架初始化时出现错误所抛出的异常
AbpDbConcurrencyException
当 EF Core 执行数据库操作时产生了 DbUpdateConcurrencyException 异常
的时候 Abp 会封装为本异常并且抛出
AbpValidationException
用户调用接口时,输入的DTO 参数有误会抛出本异常
BackgroundJobException
后台作业执行过程中产生的异常
EntityNotFoundException
当仓储执行 Get 操作时,实体未找到引发本异常
UserFriendlyException
如果用户需要将异常信息发送给前端,请抛出本异常
AbpRemoteCallException
远程调用一场,当使用 Abp 提供的 AbpWebApiClient 产生问题的时候
会抛出此异常
注:这些异常是有顺序的~


一 启动流程

Abp 框架针对异常拦截的处理主要使用了 ASP .NET CORE MVC 过滤器机制,当外部请求接口的时候,所有异常都会被 Abp 框架捕获。Abp 异常过滤器的实现名称叫做 AbpExceptionFilter,它在注入 Abp 框架的时候就已经被注册到了 ASP .NET Core 的 MVC Filters 当中了。具体流程图如下:

2 代码分析

2.1异常返回

 abp 本身针对异常信息的核心处理就在于它的 AbpExceptionFilter 过滤器,过滤器实现很简单。它首先继承了 IExceptionFilter 接口,实现了其 OnException() 方法,只要用户请求接口的时候出现了任何异常都会调用 OnException() 方法。而在 OnException() 方法内部,Abp 根据不同的异常类型进行了不同的异常处理。

 粘贴图片

粘贴图片

返回值格式:

粘贴图片

此处就是返回的错误码部分,HttpStatusCode默认指定成了500,对前端判断来说有歧义。对于一些默认封装好的处理Http请求的组件,有一部分是不支持开发者去处理这个500以上的错误信息的,或者这个错误码对于一些前端开发来说很困惑。 因为一般500的错误都是服务器发生了异常,被动的抛出的一个错误,在很多客户端是不给用户展示的,所以一些HttpClient对500以上的错误就默认处理,提示发生服务器内部错误,在自己内部消化了这个错误导致开发人员不能自由的处理Http请求

3 自定义异常处理

3.1 添加一个CustomeException.cs,继承UserFriendlyException,添加一个属性HttpCode

/// <summary>
/// 自定义错误状态吗
/// </summary>
public class CustomeException : UserFriendlyException
{
public CustomeException(int code, string message, string details)
: this((int)HttpStatusCode.BadRequest, code, message, details)
{
}
 
public CustomeException(HttpStatusCode httpCode, int code, string message, string details)
: this((int)httpCode, code, message, details)
{
}
 
public CustomeException(int httpCode, int code, string message, string details)
: base(code, message, details)
{
HttpCode = httpCode;
}
/// <summary>
/// http 状态码
/// </summary>
public int HttpCode { get; set; }
}
3.2 添加CustomeApiExceptionFilterAttribute,继承AbpApiExceptionFilterAttribute,然后重写GetStatusCode方法

public class CustomeApiExceptionFilterAttribute : AbpApiExceptionFilterAttribute, ITransientDependency
    {
        public CustomeApiExceptionFilterAttribute(IAbpWebApiConfiguration configuration) : base(configuration)
        {
        }

        protected override HttpStatusCode GetStatusCode(HttpActionExecutedContext context)
        {
            var customException = (context.Exception as CustomeException);
            if (customException != null)
            {
                return
    (HttpStatusCode)customException.HttpCode;
            }
            else
            {
                return base.GetStatusCode(context);
            }
        }

        public void UseThis()
        {
            var filters = Configuration.HttpConfiguration.Filters;
            var filterInfo = filters.FirstOrDefault(h => h.Instance is AbpApiExceptionFilterAttribute);
            if (filterInfo != null) {
                filters.Remove(filterInfo.Instance);
            }
            
            filters.Add(this);
        }
    }
3.3 在statup文件中注册重写的过滤器

注意代码中的的数字,测试发现如果不加入手动排序,ioc容器会把重写的过滤器置于次要地位,过滤器会不起作用

  services.AddMvc(
                options => {
                    options.Filters.AddService(typeof(CustomeApiExceptionFilter), order: 0);
                    options.Filters.Add(new AutoValidateAntiforgeryTokenAttribute());
                }
            ).AddJsonOptions(options => options.SerializerSettings.DateFormatString = "yyyy-MM-dd HH:mm:ss")
             .AddWebApiConventions();

以上三个步骤之后,在代码中抛出CustomeException就可以自定义httpStatusCode了。



 推荐知识

 历史版本

修改日期 修改人 备注
2020-06-04 17:12:01[当前版本] 李晶晶 1.0

 附件

附件类型

PNGPNG

知识分享平台 -V 4.8.7 -wcp