问题

在使用 Abp 框架的后台作业时,当后台作业抛出异常,会导致整个程序崩溃。在 Abp 框架的底层执行后台作业的时候,有 try/catch 语句块用来捕获后台任务执行时的异常,但是在这里没有生效。

原始代码如下:

public class TestAppService : ITestAppService{private readonly IBackgroundJobManager _backgroundJobManager;

public TestAppService(IBackgroundJobManager backgroundJobManager){        _backgroundJobManager = backgroundJobManager;    }

public Task GetInvalidOperationException(){throw new InvalidOperationException("模拟无效操作异常。");    }

public async Task<string> EnqueueJob(){await _backgroundJobManager.EnqueueAsync<BG, string>("测试文本。");

return "执行完成。";    }}

public class BG : BackgroundJob<string>, ITransientDependency{private readonly TestAppService _testAppService;

public BG(TestAppService testAppService){        _testAppService = testAppService;    }

public override async void Execute(string args){await _testAppService.GetInvalidOperationException();    }}

调用接口时的效果:

原因

出现这种情况是因为任何异步方法返回 void 时,抛出的异常都会在 async void 方法启动时,处于激活状态的同步上下文 (SynchronizationContext) 触发,我们的所有 Task 都是放在线程池执行的。

所以在上述样例当中,此时 AsyncVoidMethodBuilder.Create() 使用的同步上下文为 null ,这个时候 ThreadPool 就不会捕获异常给原有线程处理,而是直接抛出。

线程池在底层使用 AsyncVoidMethodBuilder.Craete() 所拿到的同步上下文,所捕获异常的代码如下:

internal static void ThrowAsync(Exception exception, SynchronizationContext targetContext){var edi = ExceptionDispatchInfo.Capture(exception);

if (targetContext != null)    {try        {            targetContext.Post(state => ((ExceptionDispatchInfo)state).Throw(), edi);return;        }catch (Exception postException)        {            edi = ExceptionDispatchInfo.Capture(new AggregateException(exception, postException));        }    }}

虽然你可以通过挂载 AppDoamin.Current.UnhandledException 来监听异常,不过你是没办法从异常状态恢复的。

参考文章:

Stephen Cleary:https://msdn.microsoft.com/en-us/magazine/jj991977.aspx

Jerome Laban's:https://jaylee.org/archive/2012/07/08/c-sharp-async-tips-and-tricks-part-2-async-void.html

布鲁克石:https://www.cnblogs.com/brookshi/p/5240510.html

解决

可以使用 AsyncBackgroundJob<TArgs> 替换掉之前的 BackgroundJob<TArgs> ,只需要实现它的 Task ExecuteAsync(TArgs args) 方法即可。

public class BGAsync : AsyncBackgroundJob<string>,ITransientDependency{private readonly TestAppService _testAppService;

public BGAsync(TestAppService testAppService){        _testAppService = testAppService;    }

protected override async Task ExecuteAsync(string args){await _testAppService.GetInvalidOperationException();    }}

原文地址:https://www.cnblogs.com/myzony/p/10647460.html

.NET社区新闻,深度好文,欢迎访问公众号文章汇总 http://www.csharpkit.com 

为什么不要使用 async void相关推荐

  1. C# async await 学习笔记2

    C# async await 学习笔记1(http://www.cnblogs.com/siso/p/3691059.html) 提到了ThreadId是一样的,突然想到在WinForm中,非UI线程 ...

  2. C# 中的Async 和 Await 的用法详解

    众所周知C#提供Async和Await关键字来实现异步编程.在本文中,我们将共同探讨并介绍什么是Async 和 Await,以及如何在C#中使用Async 和 Await. 同样本文的内容也大多是翻译 ...

  3. [转]小心C# 5.0 中的await and async模式造成的死锁

    原文链接 https://www.cnblogs.com/OpenCoder/p/4434574.html 内容 UI Example Consider the example below. A bu ...

  4. C# 5.0中引入了async 和 await

    C# 5.0中引入了async 和 await.这两个关键字可以让你更方便的写出异步代码. 看个例子: [csharp] view plaincopy public class MyClass { p ...

  5. 多线程编程学习笔记——async和await(三)

    接上文 多线程编程学习笔记--async和await(一) 接上文 多线程编程学习笔记--async和await(二) 五.   处理异步操作中的异常 本示例学习如何在异步函数中处理异常,学习如何对多 ...

  6. 异步/等待-什么时候返回Task vs void?

    本文翻译自:async/await - when to return a Task vs void? Under what scenarios would one want to use 在什么情况下 ...

  7. 异步的两种写法: async 与 BeginInvoke

    现在要实现异步只要用关键字async/await就可以轻松实现,在此之前需要用到委托/回调等一堆东西. 对一下是对比写法: 1 class Program 2 { 3 delegate string ...

  8. 【转载】 C# 中的Async 和 Await 的用法详解

    众所周知C#提供Async和Await关键字来实现异步编程.在本文中,我们将共同探讨并介绍什么是Async 和 Await,以及如何在C#中使用Async 和 Await. 同样本文的内容也大多是翻译 ...

  9. async/await的实质理解

    async/await关键字能帮助开发者更容易地编写异步代码.但不少开发者对于这两个关键字的使用比较困惑,不知道该怎么使用.本文就async/await的实质作简单描述,以便大家能更清楚理解. 一.a ...

最新文章

  1. 利用CSS实现文本省略效果
  2. Codeforces Round #403 (Div. 1, based on Technocup 2017 Finals)
  3. linux剧集nfo生成器,精彩LINUX软件推荐
  4. Postman批量跑接口
  5. 低学历程序员的红利来了,这个政策来的太惊喜!
  6. oracle活跃用户,监控数据库中的活跃用户及其运行
  7. 计算机组织与结构实验,计算机组织与结构实验报告 CQUPT
  8. GIL对多线程的影响
  9. devops实践指南_开发DevOps的实用指南:减少八卦的步骤
  10. 推荐一款eclipse快速打开项目文件夹所在路径插件
  11. C语言学习笔记---枚举类型enum
  12. 耶路撒冷三千年(笔记)
  13. 利用SMB协议共享电脑文件,发挥ipad生产力
  14. 压缩的Swf文件利用Python解压
  15. 谷歌浏览器能打开网页微信_Chrome浏览器打开微信页面-Go语言中文社区
  16. 易语言取php网页数据,易语言爬取网页内容方法
  17. vue 图片转base64的两种方法(包括h5+plus调取手机图片)
  18. 论文分析---APP恶意软件检测
  19. php5.3 pear,php-5.3 下安装pear 和 pecl
  20. 缓存区 buffers 和 caches 的区别

热门文章

  1. 如何在Android主屏幕上添加热点快捷方式
  2. java swing列表数据加监听,【Java Swing公开课|Java监听列表项选择事件怎么用,看完这篇文章你一定就会了】- 环球网校...
  3. 一份详尽的利用 Kubeadm部署 Kubernetes 1.13.1 集群指北
  4. GDUFE ACM-1045
  5. 关于Virtual-Hosting的理解
  6. 27个赢得别人欣赏的诀窍
  7. 八款Js框架介绍及比较~转载
  8. [导入]php 安全基础 第八章 共享主机 文件系统浏览
  9. Xamarin效果第十五篇之自定义CheckBox
  10. 4. 堪比JMeter的.Net压测工具 - Crank 进阶篇 - 认识wrk、wrk2