为什么不要使用 Async Void ?
问题
在使用 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
解决
可以使用 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();
    }
}为什么不要使用 Async Void ?的更多相关文章
- 为什么不要使用 async void?
		问题 在使用 Abp 框架的后台作业时,当后台作业抛出异常,会导致整个程序崩溃.在 Abp 框架的底层执行后台作业的时候,有 try/catch 语句块用来捕获后台任务执行时的异常,但是在这里没有生效 ... 
- 《C#并发编程经典实例》学习笔记—2.9 处理 async void 方法的异常
		问题 需要处理从 async void 方法传递出来的异常. 解决方案 书中建议尽量不写 async void 这样的方法,如果非写不可,建议在方法内部 try catch 所有的代码,即在方法内部处 ... 
- 处理async void 方法中无法捕捉异常信息
		利用 NuGet库 Nito.AsyncEx 中的 AsyncContext类. 添加NuGet类库,使用AsyncContext AsyncContext.Run(Action action); 
- [C#] async 的三大返回类型
		async 的三大返回类型 序 博主简单数了下自己发布过的异步文章,已经断断续续 8 篇了,这次我想以 async 的返回类型为例,单独谈谈. 异步方法具有三个可让开发人员选择的返回类型:Task&l ... 
- async & await 的前世今生(Updated)
		async 和 await 出现在C# 5.0之后,给并行编程带来了不少的方便,特别是当在MVC中的Action也变成async之后,有点开始什么都是async的味道了.但是这也给我们编程埋下了一些隐 ... 
- [.NET] 怎样使用 async & await 一步步将同步代码转换为异步编程
		怎样使用 async & await 一步步将同步代码转换为异步编程 [博主]反骨仔 [出处]http://www.cnblogs.com/liqingwen/p/6079707.html ... 
- [.NET] 利用 async & await 进行异步 IO 操作
		利用 async & await 进行异步 IO 操作 [博主]反骨仔 [出处]http://www.cnblogs.com/liqingwen/p/6082673.html 序 上次,博主 ... 
- await and async
		Most people have already heard about the new “async” and “await” functionality coming in Visual Stud ... 
- C#~异步编程再续~await与async引起的w3wp.exe崩溃-问题友好的解决
		返回目录 关于死锁的原因 理解该死锁的原因在于理解await 处理contexts的方式,默认的,当一个未完成的Task 被await的时候,当前的上下文将在该Task完成的时候重新获得并继续执行剩余 ... 
随机推荐
- Android 实现朋友圈有图片和视频
			最近开发比较烦,这个作为我第一篇博客吧. 效果就是图上的样子. 首先是布局文件,没什么就是一个RecycleView <android.support.v7.widget.RecyclerVie ... 
- mvc中尽量避免使用HttpContext.Current.Request
			在Mvc开发中滥用HttpContext.Current.Request,可能会造成非IE浏览器重复加载页面的情况. 不管你信不,反正我在Mvc3.0中遇到过. 
- Cordova各个插件使用介绍系列(八)—$cordovaCamera筛选手机图库图片并显示
			原文档请看http://www.ncloud.hk/%E6%8A%80%E6%9C%AF%E5%88%86%E4%BA%AB/ionic%E5%9B%BE%E7%89%87%E4%B8%8A%E4%B ... 
- 视频SharePoint 2010 大局观 By 陈希章[zt]
			SharePoint 2010 大局观 By 陈希章 http://hi.baidu.com/jinzesudawei/item/9d0adace8cbcaf2c47d5c0fc 
- check_mk 分布式监控
			http://mathias-kettner.com/checkmk_wato_distributed.html peer(贵族) 管理多个slave 复制配置文件 /etc/check_mk/con ... 
- powershell解决win10开始菜单和通知中心无法打开
			然后通过 Ctrl + Shift + Esc 弹出任务管理器点击文件-->运行新任务 在打开的填写框里面输入 "powershell"同时勾选下方的"以管理员身份 ... 
- github设置添加SSH(转载自:破男孩)
			注:本文来源于 破男孩 博客(http://www.cnblogs.com/ayseeing/p/3572582.html)能切实解决问题. 很多朋友在用github管理项目的时候,都是直接使用htt ... 
- Next K Permutation
			3457: Next K Permutation 时间限制: 1 Sec 内存限制: 128 MB提交: 4 解决: 4[提交] [状态] [讨论版] [命题人:admin] 题目描述 n 个数有 ... 
- node.js 练习1
			1.利用editplus 创建 n1.js 文件 2.输入代码 3.打开cmd 输入 node n1.js 4.打开浏览器 输入 localhost:8000 5.再次回看 cmd 
- HttpHandler(处理程序) 和 HttpModule(托管模块)
			本文参见:http://www.tracefact.net/Asp-Net/Introduction-to-Http-Handler.aspx 前言:前几天看到一个DTcms网站,里面有个伪静态技术, ... 
