2015-11-04 15 views
3

我不明白這兩個調用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框架這是被稱爲通過。尤瓦爾的解釋清除了所有這些,並且是正確的。

+0

你打電話給'Caller1'和'Caller2'怎麼樣? –

+0

Caller1和Caller2是由Azure WebJobs SDK調用的公共方法。 SDK支持異步方法。 –

回答

3

您的兩個方法調用之間的區別是前者在被調用時異步等待使用await。因此,TaskCanceledException從內部SendEmailAsync調用傳播,這是由於您未等待using範圍內的異步方法而導致的,這會導致處置SmtpClient與異步調用結束之間的爭用情況。而在後者中,例外被封裝在返回Task對象中,我不確定您是否在等待。這就是爲什麼前者會立即看到異常情況。

應該做的第一件事是正確地等待上SendEmailAsync網關內:

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

然後,您可以使用它避免了創建狀態機的開銷第二種方法。不同之處在於,您保證SmtpClient只有在異步操作完成後纔會處理。

+0

如果我有這個正確的話:我不應該從一個對象中返回一個任務,而不需要等待該對象的using語句。這是因爲在任務完成之前對象可能會被處置掉。是對的嗎? –

+0

@BrianVallelunga沒錯。 –

+0

而且我的Caller2方法似乎也造成了我沒有捕獲的異常,但WebJobs框架正在捕獲和重試。 –

相關問題