小弟初来乍到,分享一些工作学习中遇到的问题和解决方式,如有不准确或是有错误的地方,希望不吝赐教,谢过了。  --Dogtwo

起因:
ABP 中异常处理的思路是很清晰的。一共五种类型的异常类。

AbpInitializationException用于封装ABP初始化过程中出现的异常,只要抛出AbpInitializationException异常就可以,无须做额外处理。这类异常往往是需要维护人员介入分析的。

其他四个异常都在AbpController中被集中处理,处理分为两步:一,通过EventBus触发异常事件,相应的异常处理函数则处理异常。二,针对AbpValidationException,UserFriendlyException和AbpAuthorizationException异常,Abp会将异常信息转换为ErrorInfo,并以view或Json的形式返回给客户端。
(以上内容摘自 HK Zhand大大的博客

我们应使用UserFriendlyException来包装我们自定义的异常,但UserFriendlyException抛出的异常存在一个问题:无法指定HttpStatus code,这样前端收到的response中HttpStatus code均为500。对一部分前端语言或框架来说,这个状态码难以处理或不便于处理,因为约定5xx指示服务器异常,不应再由前端进行Handle。

所以,我们希望更改Response中的HttpStatus code。

思路很简单,我们利用filter去拦截异常,判断其类型,若为我们自定义的异常则更改HttpStatus code。

Filter部分代码

 public class MyExceptionFilter : IExceptionFilter
{
public ILogger Logger { get; set; } public MyExceptionFilter()
{
Logger = NullLogger.Instance;
} public void OnException(ExceptionContext context)
{
if (!(context.Exception is MyException))
{
return;
} HandleAndWrapException(context);
} private void HandleAndWrapException(ExceptionContext context)
{
context.HttpContext.Response.StatusCode = (int)HttpStatusCode.BadRequest; var myException = (MyException)context.Exception; context.Result = new ObjectResult(
  new AjaxResponse(
    new ErrorInfo(myException.ErrorCode, myException.Message)
        )
     ); LogHelper.LogException(Logger, context.Exception); context.Exception = null; //Handled!
}
}

然后再StartUp文件中添加filter

 services.Configure(mvcOptions =>
{
mvcOptions.Filters.AddService(typeof(MyExceptionFilter ));
});

运行发现,filter并不能catch住我们抛出的异常,甚至OnException方法体都没进入。
原来,ABP本身实现了几个filter,包括Authorization Filter, Audit Action Filter, Validation Action Filter, Unit of Work Action Filter, Exception Filter和Result Filter.
造成我们的自定义filter无法正常执行的原因就是Exception Filter.

ABP官方文档介绍为:
AbpExceptionFilter is used to handle exceptions thrown from controller actions. It handles and logs exceptions and returns a wrapped response to the client.

This only handles object results, and not view results. Actions returning any object, JsonResult or ObjectResult will be handled. Actions are not handled if they return a view or any other result type implementing IActionsResult. It is recommend that you use the built-in UseExceptionHandler extension method defined in the Microsoft.AspNetCore.Diagnostics package to handle view exceptions.
Exception handling and logging behaviour can be changed using the WrapResult and DontWrapResult attributes for methods and classes.

除此之外, ABPExceptionFilter还会触发AbpHandledExceptionData eventbus event.且,经由ABPExceptionFilter处理之后,会将异常信息转换为ErrorInfo,并以view或Json的形式返回给客户端。所以当response通过ABPExceptionFilter之后便不再包含Exception了,自然我们的Filter捕捉不到了。

由此,想到两个解决方法
一 经由Event bus再次将异常抛出(很明显,如果是为了解决本问题的话,逻辑不通,很差的解决方式。已经被catch的异常再抛出来被自定义的filter去处理,七擒孟获)
但为了熟悉这部分的代码逻辑还是做了一下实现。

 public class MyExceptionHandler : IEventHandler, ITransientDependency
{
public ILogger Logger { get; set; } public MyExceptionHandler()
{
Logger = NullLogger.Instance;
} public void HandleEvent(AbpHandledExceptionData eventData)
{
Logger.Info(eventData.Exception.ToString());
throw eventData.Exception;
}
}

如果是为了别的一些功能,上面利用EventBus来处理的方式也可以借鉴。

二是禁用ABPExceptionFilter改为使用我们自己的filter

禁用ABPExceptionFilter
除上面声明Filter之外还需要在Configure中app.UseMvc之后添加

// Remove AbpExceptionFilter
var ops = app.ApplicationServices.GetRequiredService<IOptions<MvcOptions>>().Value;
var abpExceptionFilter = ops.Filters.FirstOrDefault(f =>
(f as ServiceFilterAttribute)?.ServiceType == (typeof(AbpExceptionFilter)));
ops.Filters.Remove(abpExceptionFilter);

此方法也有不好的地方,即除我们自定义的异常外,其他异常并不能再由ABPExceptionFilter来处理。

改良最佳版:
我们的最根本的目的其实是更改HttpStatusCode,所以即便Exception被ABPExceptionFilter 封装成ErrorInfo来说对我们影响并不大,只要能让我们的自定义Filter catch住异常即可,因此,在Configuresevice中注册filter时声明顺序即可。

options.Filters.AddService(typeof(myExceptionFilter), order: );

另:由ABPExceptionFilter介绍可知,它并不会catch住所有类型的异常,如果想对任意类型的异常进行处理,使用middleware可能会更好。

参考内容:

github:
https://github.com/aspnetboilerplate/aspnetboilerplate/issues/1550
https://github.com/aspnetboilerplate/aspnetboilerplate/issues/3280

sessionliang大佬的博客

HK Zhang大佬的博客

ABP Changing Httpcode status的更多相关文章

  1. clear read-only status问题的解决

    IDEA系工具可能会报出的错误. 解决方法见官方文档吧:Changing Read-Only Status of Files  : https://www.jetbrains.com/help/ide ...

  2. words

    conscious[英][ˈkɒnʃəs][美][ˈkɑnʃəs]consensus[英][kənˈsensəs][美][kənˈsɛnsəs] scious sensuswaterflood; de ...

  3. SQLSERVER全文搜索

    SQLSERVER全文搜索 看这篇文章之前请先看一下下面我摘抄的全文搜索的MSDN资料,基本上MSDN上关于全文搜索的资料的我都copy下来了 并且非常认真地阅读和试验了一次,并且补充了一些SQL语句 ...

  4. xp+WinDBG+VMware调试内核

    呵呵,搞点突兀的标题而已.其实说的还是如何使用WinDBG和VMware来搭建调试内核的环境而已,这些网上已经有数不清的教程了,不过我喜欢自己亲手写一下.第一,把这个过程写一遍能加深印象,就算以后忘记 ...

  5. oracle11g中SQL优化(SQL TUNING)新特性之SQL Plan Management(SPM)

    1.   简介 Oracle Database11gR1引进了SQL PlanManagement(简称SPM),一套允许DBA捕获和保持任意SQL语句执行计划最优的新工具,这样,限制了刷新优化器统计 ...

  6. APPCORE Routine APIs

    Introduction to APPCORE Routine APIs This chapter provides you with specifications for calling many ...

  7. Mysql 5.7 基于组复制(MySQL Group Replication) - 运维小结

    之前介绍了Mysq主从同步的异步复制(默认模式).半同步复制.基于GTID复制.基于组提交和并行复制 (解决同步延迟),下面简单说下Mysql基于组复制(MySQL Group Replication ...

  8. CloudSim源代码学习——任务单元(Cloudlet)

    /* * Title: CloudSim Toolkit * Description: CloudSim (Cloud Simulation) Toolkit for Modeling and Sim ...

  9. SQL Server全文搜索

    SQL Server全文搜索 看这篇文章之前请先看一下下面我摘抄的全文搜索的MSDN资料,基本上MSDN上关于全文搜索的资料的我都copy下来了 并且非常认真地阅读和试验了一次,并且补充了一些SQL语 ...

随机推荐

  1. 一招让 IOS 自动化化快的飞起

    前言 最近在做IOS自动化测试,IOS的Appium环境都配置OK,Demo脚本运行没有问题,多开执行没有问题,IOS安卓统一平台调度集成没有问题,可以进行自动化测试.课时真正执行用例时发现个严重问题 ...

  2. CentOS7 openssh7.9p1安装

    先安装telnet,以防安装ssh出现问题,无法远程登录设备. 最新版openssh下载地址:http://www.openssh.com/ftp.html 一.安装telnet和xinetd: 1. ...

  3. 深入-FastReport TfrxReport组件使用

    [翻译] FastReport TfrxReport组件使用   一:加载和保存报表 报表默认保存在项目窗体文件中,大多数情况下,没有更多的操作要深圳市, 因此,你不需要采取特别措施来载入报告.如果你 ...

  4. PHP中 PCRE正则表达式模式修饰符“u” 的使用。

    u (PCRE_UTF8) 此修正符打开一个与 perl 不兼容的附加功能. 模式字符串被认为是utf-8的. 这个修饰符 从 unix 版php 4.1.0 或更高,win32版 php 4.2.3 ...

  5. CLion之C++框架篇-安装工具,基础框架的搭建(一)

      背景   日常学习C++,也就是看看书.在vim里写写代码.在日常项目开发中,也是边看书(一是系统性理解.二是找找有什么更好的代码编写方式)边写代码,会顺带看看别人的代码怎么写的?     日常学 ...

  6. 笔记:安卓App消息处理机制

    内容简述 类似Binder机制,MessageQueue.Looper也有底层的C++实现,涉及文件管道和驱动等. 以下仅从Java层的Looper.Handler和MessageQueue等相关类型 ...

  7. C#基础笔记

    第一章: 1.C#创建程序的基本结构 class 类名 { static void Main(string[]args) { } } 注意:1)namespace2)using3)类名命名规则:字母. ...

  8. 浅谈 Nginx 的内部核心架构设计

    一.前言 Nginx---Ngine X,是一款免费的.自由的.开源的.高性能HTTP服务器和反向代理服务器:也是一个IMAP.POP3.SMTP代理服务器:Nginx以其高性能.稳定性.丰富的功能. ...

  9. 从前端中的IOC理念理解koa中的app.use()

    忙里偷闲,打开平时关注的前端相关的网站,浏览最近最新的前端动态.佼佼者,平凡的我做不到,但还是要争取不做落后者. 前端中的IoC理念,看到这个标题就被吸引了.IoC 理念,不认识呢,点击去一看,果然没 ...

  10. Aseprite+Cocos:打包像素画图,导入到cocos里并动起来

    前言:Aseprite入门教程            Aseprite入门:第一个gif动图 1.制作像素画: 按照上一次的小球跳动制作过程,先制作一个像素画动画: 若是导出gif动态图,效果如下: ...