编程语言
首页 > 编程语言> > c# – 使用SendMailAsync的TaskCanceledException的原因?

c# – 使用SendMailAsync的TaskCanceledException的原因?

作者:互联网

我不明白这两个调用SendMailAsync的实现之间的区别.大多数时候第一次,我收到一个TaskCanceledException,但是第二次,一切都按预期工作.

我认为这两种消费方法是等价的,但显然我错过了一些东西.

这似乎与:TaskCanceledException when not awaiting有关,但相反:

// Common SmtpEmailGateway library
public class SmtpEmailGateway : IEmailGateway
{
    public Task SendEmailAsync(MailMessage mailMessage)
    {
        using (var smtpClient = new SmtpClient())
        {
            return smtpClient.SendMailAsync(mailMessage);
        }
    }
}

// Caller #1 code - Often throws TaskCanceledException
public async Task Caller1()
{
     // setup code here
     var smtpEmailGateway = new SmtpEmailGateway();
     await smtpEmailGateway.SendEmailAsync(myMailMessage);
}

// Caller #2 code - No problems
public Task Caller2()
{
     // setup code here
     var smtpEmailGateway = new SmtpEmailGateway();
     return smtpEmailGateway.SendEmailAsync(myMailMessage);
}

编辑:事实证明,Caller2方法也导致异常,我只是没有看到它们,因为WebJobs框架被调用了. Yuval的解释清除了所有这一切并且是正确的.

解决方法:

两个方法调用之间的区别在于前者在被调用时异步等待使用await.因此,TaskCanceledException从内部SendEmailAsync调用传播,这是由于您没有等待使用范围中的异步方法,这导致处理SmtpClient和异步调用结束之间的竞争条件.在后者中,异常被封装在返回的Task对象中,我不确定你是否在等待.这就是为什么在前者中,你会立即看到异常.

应该做的第一件事是在网关内正确等待SendEmailAsync:

public class SmtpEmailGateway : IEmailGateway
{
    public async Task SendEmailAsync(MailMessage mailMessage)
    {
        using (var smtpClient = new SmtpClient())
        {
            return await smtpClient.SendMailAsync(mailMessage);
        }
    }
}

然后,您可以使用第二种方法,避免创建状态机的开销.不同的是,现在您要保证SmtpClient只会在异步操作完成后才会处置.

标签:c,async-await,smtpclient
来源: https://codeday.me/bug/20190516/1116617.html