【问题标题】:Async methods called from UnhandledException handler don't get awaited不等待从 UnhandledException 处理程序调用的异步方法
【发布时间】:2019-12-06 16:04:20
【问题描述】:

在我的App.xaml.cs 中,我创建了一个处理程序来响应AppDomain.CurrentDomain.UnhandledException 事件。

在处理程序内部,我需要调用一个异步方法来发送有关错误的电子邮件报告。所以我在等待方法,在里面我在等待Net.Mail.SmtpClient.SendMailAsync()

但这不起作用——当控件到达第二个等待时(就在实际发送之前),应用程序退出。

当我摆脱所有异步并使用同步替代方案 Net.Mail.SmtpClient.Send() 时,电子邮件会正确发送。

在处理程序中似乎没有抛出其他异常。另外,这似乎不仅仅是 Visual Studio 调试模式的问题。

在 UnhandledException 处理程序中不能成功调用异步方法吗?

更新:

我的处理程序方法的签名如下所示:

private async void CurrentDomain_UnhandledException(object sender, UnhandledExceptionEventArgs e);

我将处理程序附加到App 的构造函数中的事件,如下所示:

App()
{
    AppDomain.CurrentDomain.UnhandledException += CurrentDomain_UnhandledException;
}

【问题讨论】:

标签: c# .net wpf asynchronous .net-4.7.2


【解决方案1】:

事件总是void。这意味着如果你想使用await,你必须使用async void。这就是您在此处看到的问题的原因。

await 作用于一个不完整的Task 时,该方法的其余部分在等待后调度完成,并且它返回。通常它返回一个调用者可以等待的Task,但由于返回类型是void,它什么也不返回。调用者不能等待它,即使它想要。通常这不是事件的问题,因为事件只是“某事”发生的通知,并且触发事件的任何事情都不依赖于事件处理程序内部发生的任何事情。

但在这种情况下,框架会在事件处理程序返回后继续关闭应用程序。因此,自从await 返回后,应用程序在不等待任务实际完成的情况下关闭。

您最好的解决方案是让您的事件处理程序中的所有内容保持同步。这将防止它在您期望它之前返回。

“保持一切同步”是指实际使用同步方法(如Net.Mail.SmtpClient.Send())。不要在异步方法上同步等待,因为can cause deadlocks

【讨论】:

  • 糟糕,抱歉。我粘贴了我暂时使用的处理程序的同步版本。签名确实包含async
  • @zvizesna 是的,我认为您已经在使用 async void。这就是我的答案所针对的。您需要删除 async 并仅在处理程序中使用同步方法。
  • 一般建议是永远不要使用async void,除非你绝对必须这样做。与任何其他异步返回类型相比,它具有独特的行为,并且往往会导致类似这样的不那么明显的问题。
  • @CaptainPrinny 我不会说“从不”。编译器没有完全禁止它的事实意味着它有它的位置。 Microsoft uses the word "avoid" 唯一的例外是事件处理程序(即唯一可接受的用途是在事件处理程序中)。但是,在某些事件中,在事件处理程序完成后会立即发生其他一些事情,async void 将无法正常工作。
  • 是的,这主要是我的呼应。我的意思是“一般建议 => 从不”近似于“如果你不知道你需要使用这个的事实,不要”
猜你喜欢
  • 2016-12-22
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多