问题

在使用 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. Tips/Tricks#0:母版页中对控件ID的处理
  2. MATLAB实战系列(四)-导入txt文件技巧大全
  3. QT的QBrush类的使用
  4. 游戏安全有多重要?——GAME-TECH游戏开发者技术沙龙
  5. 训练集样本不平衡问题对CNN的影响
  6. javaScript一种优化模式-初始化时分支
  7. screw ---- 数据库转文档
  8. u盘读写测试_aigo U395固态U盘评测,速度可能会吓到你,价格很良心
  9. 如何批量将多个 PDF 文档转为 XPS 格式
  10. php的表达爱意的一句代码,表达爱意的诗句15个字
  11. word_excel_office向程序发送命令时出现问题
  12. 笔记本电脑的计算机名称在哪里看,如何查看笔记本电脑的IP地址
  13. contiki 操作教程
  14. 2022-7 刷题记录
  15. 群晖服务器主板维修,没那么复杂 群晖DS213j内部拆解
  16. Qt的.pro文件简介
  17. 全面解读居住证积分新政,赶紧看看你离落户上海还有多远!
  18. 日均调用量超13亿次,阿里达摩院研发全球首个实时翻译直播-1
  19. L*MM 文件管理器小结
  20. CSDN文本MD编辑器教程【始终专一MD】

热门文章

  1. 在Linux上按大小列出文件和目录
  2. 『中级篇』Dockerfile详解(17)
  3. 免杀新姿势:利用线程将恶意代码注入到内存中
  4. 4. MyBatis几个可以优化的地方
  5. 黄聪:Microsoft Enterprise Library 5.0 系列教程(四) Logging Application Block
  6. 腾讯急招多名.NET Core,5年30k!
  7. 使用Spectre.Console创建漂亮的控制台应用程序
  8. 使用.NET5、Blazor和Electron.NET构建跨平台桌面应用
  9. 十个现象,识别程序员的“水份”
  10. 杀鸡焉用牛刀!放下Windbg,让dotnet-stack来快速定位死锁原因