对如何构建调用 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.RunTask.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)
    {
        // ...
    }
}