来自Task.StartNew的异常传播

时间:2015-09-16 12:32:53

标签: c# async-await task semaphore

考虑以下代码:

<td>
    <a href="@Url.Action("MemberEmployees", "Employees", new { @item.MemberId })"><span title="Personel" class="btn btn-default btn-sm fa fa-user" /></a>
    <a href="@Url.Action("Index", "Documents",new { @item.MemberId })"><span title="Belgeler" class="btn btn-default btn-sm fa fa-inbox" /></a>
    <a href="@Url.Action("Index", "Logs",new { @item.MemberId })"><span title="Kayıtlar" class="btn btn-default btn-sm fa fa-folder" /></a>
    <a href="@Url.Action("Edit", "Members", new { @item.MemberId })"><span title="Araçlar" class="btn btn-default btn-sm fa fa-truck" /></a>
    <a href="@Url.Action("Edit", "Members", new { @item.MemberId })"><span title="Güncelle" class="btn btn-default btn-sm fa fa-pencil" /></a>
    <a class="modal-link" href="@Url.Action("Delete", "Members",new { @item.MemberId })"><span title="Sil" class="btn btn-danger btn-sm fa fa-trash" /></a>
</td>

如果在任务委托中抛出异常,它就永远不会传播到调用方法。我无法等待信号量内的任务,因为在这种情况下,信号量将被等待的任务阻止。有没有办法将异常传播给调用方法。

2 个答案:

答案 0 :(得分:1)

你遇到两个问题: 与传统的void方法相比,async void的错误处理略有不同:虽然StartReceiveMessagesAsync调用了GetAmazonMwsNotifications,但它阻止GetAmazonMwsNotifications直到第一个await(开启到达未完成的任务),StartReceiveMessagesAsync内的任何异常都不会被退回GetAmazonMwsNotifications。在非UI应用程序中,它们总是被抛到线程池上,导致应用程序关闭(我不知道UI应用程序在这种情况下如何工作)。

那么为什么你的应用程序不会死? 异常没有抛到堆栈上,它被设置到Task.Factory.StartNew返回的任务上,并且没有观察到该任务(既不通过await也不通过.Wait())。在某些时候,垃圾收集器将运行以收集该任务,此时将在应用程序域上抛出UnobservedTaskException。如果没有观察到这一点,你的应用程序最终会崩溃。

在我看来,你不需要通过Task.Run/Task.Factory.StartNew卸载代码,等待ReceiveMessageAsync的结果而不是阻塞它并处理async void中的异常方法“通常”的方式;请记住,未处理的异常会导致应用程序崩溃。

答案 1 :(得分:0)

您可以使用OnlyOnFaulted选项继续执行其他任务(即已抛出异常且任务处于故障状态)。

.ContinueWith(t => { Console.WriteLine(t.Exception.Message); }, 
        TaskContinuationOptions.OnlyOnFaulted);