对如何构建调用 SmtpClient.SendMailAsync() 的 async/await 代码感到困惑
Confused on how to structure async/await code that calls SmtpClient.SendMailAsync()
我阅读了 async-await
功能的文档,但仍然对如何构建调用 SmtpClient.SendMailAsync()
方法的 async-await
代码感到非常困惑。
我应该如何重写代码才能正确使用 async-await
?
目前,我的代码如下所示:
系统会定期调用 PrivateSignal
以发送电子邮件通知。
public override void PrivateSignal(IEventInformation ev)
{
TagEvent tag = (TagEvent)ev;
Task.Run(async () =>
{
try
{
await smptClient.SendMailAsync(CaptureRC.SmptFromEmailAddr,
ToEmails,
CaptureRC.EmailSubject,
"seen moving" + tag.ToString());
}
catch (AggregateException ex)
{
//TODO handle the error
//TODO log the erros, along with
}
}).Wait();
}
async/await 是取代 Task.Run
和 Task.Wait
之类的新热点。试试这个:
public async override Task PrivateSignal(IEventInformation ev)
{
TagEvent tag = (TagEvent)ev;
try
{
await smptClient.SendMailAsync(CaptureRC.SmptFromEmailAddr,
ToEmails, CaptureRC.EmailSubject, "seen moving" + tag.ToString());
}
catch (Exception ex)
{
//TODO handle the error
//TODO log the erros, along with
}
}
await
导致 运行 线程挂起,直到任务完成(或被取消或遇到错误)。该方法的其余部分自动注册为延续。 async/await 因此是基于任务的异步编程的语法糖。
此外,避免使用 async void
方法很重要,因为 void
支持是为事件处理程序保留的。对于没有 return 值的方法,而不是 void
、return Task
。
最后,由于此方法是 override
,您还需要将基本方法的 return 类型更改为 Task
。
您还应该制作 PrivateSignal
async
,其中包括用 async
和 return 标记 Task
:
public override async Task PrivateSignalAsync(IEventInformation ev)
{
TagEvent tag = (TagEvent)ev;
try
{
await smptClient.SendMailAsync(CaptureRC.SmptFromEmailAddr, ToEmails, CaptureRC.EmailSubject, "seen moving" + tag.ToString());
}
catch (Exception ex)
{
// ...
}
}
不过,您似乎不能这样做,因为 PrivateSignal
正在覆盖一个已经同步的方法。如果你可以将基本方法更改为 return a Task
那么你应该,但如果你不能那么根本不要在该方法中使用 async
因为阻塞 async
会导致死锁和其他不需要的结果:
public override void PrivateSignal(IEventInformation ev)
{
TagEvent tag = (TagEvent)ev;
try
{
smptClient.SendMail(CaptureRC.SmptFromEmailAddr, ToEmails, CaptureRC.EmailSubject, "seen moving" + tag.ToString());
}
catch (Exception ex)
{
// ...
}
}
我阅读了 async-await
功能的文档,但仍然对如何构建调用 SmtpClient.SendMailAsync()
方法的 async-await
代码感到非常困惑。
我应该如何重写代码才能正确使用 async-await
?
目前,我的代码如下所示:
系统会定期调用 PrivateSignal
以发送电子邮件通知。
public override void PrivateSignal(IEventInformation ev)
{
TagEvent tag = (TagEvent)ev;
Task.Run(async () =>
{
try
{
await smptClient.SendMailAsync(CaptureRC.SmptFromEmailAddr,
ToEmails,
CaptureRC.EmailSubject,
"seen moving" + tag.ToString());
}
catch (AggregateException ex)
{
//TODO handle the error
//TODO log the erros, along with
}
}).Wait();
}
async/await 是取代 Task.Run
和 Task.Wait
之类的新热点。试试这个:
public async override Task PrivateSignal(IEventInformation ev)
{
TagEvent tag = (TagEvent)ev;
try
{
await smptClient.SendMailAsync(CaptureRC.SmptFromEmailAddr,
ToEmails, CaptureRC.EmailSubject, "seen moving" + tag.ToString());
}
catch (Exception ex)
{
//TODO handle the error
//TODO log the erros, along with
}
}
await
导致 运行 线程挂起,直到任务完成(或被取消或遇到错误)。该方法的其余部分自动注册为延续。 async/await 因此是基于任务的异步编程的语法糖。
此外,避免使用 async void
方法很重要,因为 void
支持是为事件处理程序保留的。对于没有 return 值的方法,而不是 void
、return Task
。
最后,由于此方法是 override
,您还需要将基本方法的 return 类型更改为 Task
。
您还应该制作 PrivateSignal
async
,其中包括用 async
和 return 标记 Task
:
public override async Task PrivateSignalAsync(IEventInformation ev)
{
TagEvent tag = (TagEvent)ev;
try
{
await smptClient.SendMailAsync(CaptureRC.SmptFromEmailAddr, ToEmails, CaptureRC.EmailSubject, "seen moving" + tag.ToString());
}
catch (Exception ex)
{
// ...
}
}
不过,您似乎不能这样做,因为 PrivateSignal
正在覆盖一个已经同步的方法。如果你可以将基本方法更改为 return a Task
那么你应该,但如果你不能那么根本不要在该方法中使用 async
因为阻塞 async
会导致死锁和其他不需要的结果:
public override void PrivateSignal(IEventInformation ev)
{
TagEvent tag = (TagEvent)ev;
try
{
smptClient.SendMail(CaptureRC.SmptFromEmailAddr, ToEmails, CaptureRC.EmailSubject, "seen moving" + tag.ToString());
}
catch (Exception ex)
{
// ...
}
}