2017-04-26 116 views
3

我正在爲ASP.NET身份實施EmailServer從異步方法調用同步方法

我不喜歡async...awaitusing不兼容,所以我的電子郵件方法是同步的。

那麼我怎樣才能從框架的SendAsync方法調用它?

public class EmailService : IIdentityMessageService 
{ 
    public Task SendAsync(IdentityMessage message) 
    { 
     Email email = new Email(); 
     return Task.FromResult<void>(email.Send(message)); 
    } 
} 

在上面的代碼,Task.FromResult()給我一個錯誤說void不能用來作爲參數的類型。但email.Send()返回無效!

如何走出泥潭?

+3

酷似顯示在http://stackoverflow.com/questions/16566547/do-using-statements-and-await-keywords-play-nicely-你不喜歡'using'和'async'(什麼在-C-尖銳)? –

+0

@AlexeiLevenkov:我發現有些例子說這不是有效的代碼,我看到'SmtpClient.SendAsync()'帶有第二個參數,它與回調相關。這就是我想要避免的。 –

+3

OT:[SmtpClient文檔](https://docs.microsoft.com/dotnet/api/system.net.mail.smtpclient)建議使用[MailKit](https://github.com/jstedfast/MailKit)和[MimeKit](https://github.com/jstedfast/MimeKit)。 –

回答

7

如果沒有結果,則不要嘗試返回結果。只是返回平原,完成Task

public class EmailService : IIdentityMessageService 
{ 
    public Task SendAsync(IdentityMessage message) 
    { 
     new Email().Send(message); 
     return Task.CompletedTask; 
    } 
} 

如果你是停留在前期4.6的土地,那麼你可以使用Task.FromResult<bool>(true)代替。

所有這一切說,我對你的評論感到困惑async...await是不兼容using。根據我的經驗,這很好。如果你的方法實際上是異步的,它會好得多。我認爲你應該把注意力放在如何做到這一點上,而不是用什麼最好的/正確的語法來僞造一個方法。

附錄:

我現在還不能對你對使用using關注清晰。但是,根據您的評論,似乎您想使用SmtpClient.SendAsync(),但不確定如何將其應用於async/await的上下文中。

不幸的是,即使在.NET之前,我們有很多異步方法,並且這些方法和新的等待方法使用相同的命名規則。 (要清楚:這是不幸的命名,不是異步方法存在:))。但是,在所有情況下,都有可能將舊的API適用於新的API。

在某些情況下,這與使用Task.FromAsync()方法一樣簡單。這適用於任何支持舊模型的舊模型。但SmtpClient.SendAsync()模型是基於事件的回調方法,需要稍微不同的方法。

注意:在寫下例子後,我注意到SmtpClient類有一個基於Task的異步操作方法SendMailAsync()。所以實際上,沒有必要調整舊的SendAsync()方法。但是,這是一個很有用的例子,用於說明在沒有提供基於Task的替代方案時,如何進行此類改編。

簡單地說,你可以使用TaskCompletionSourceSmtpClient對象的SendCompleted事件。這裏是什麼看起來像一個輪廓:

public class EmailService : IIdentityMessageService 
{ 
    public async Task SendAsync(IdentityMessage message) 
    { 
     // I'm not familiar with "IdentityMessage". Let's assume for the sake 
     // of this example that you can somehow adapt it to the "MailMessage" 
     // type required by the "SmtpClient" object. That's a whole other question. 
     // Here, "IdentityToMailMessage" is some hypothetical method you write 
     // to handle that. I have no idea what goes inside that. :) 
     using (MailMessage mailMessage = IdentityToMailMessage(message)) 
     using (SmtpClient smtpClient = new SmtpClient()) 
     { 
      TaskCompletionSource<bool> taskSource = new TaskCompletionSource<bool>(); 

      // Configure "smtpClient" as needed, such as provided host information. 
      // Not shown here! 

      smtpClient.SendCompleted += (sender, e) => taskSource.SetResult(true); 
      smtpClient.SendAsync(mailMessage, null); 

      await taskSource.Task; 
     } 
    } 
} 

以上將啓動異步操作,並使用SendCompleted事件的處理程序(即「回調」到該文件指)來設置結果爲TaskCompletionSource<bool>對象(結果值從來沒有真正使用,但沒有純香草Task版本的TaskCompletionSource&hellip;你必須有一些)。

它採用await,而不是直接返回taskSource.Task對象,因爲這樣它可以正確處理處置的SmtpClient對象的電子郵件操作實際上已經完成時。

+0

我有最新的一些。但是我發現了一些避免使用異步方法的「使用」塊的例子。我看起來很深入,但是'SmtpClient.SendAsync()'需要第二個參數,這在某種回調的情況下似乎是有意義的。 –

+0

如果您沒有任何需要,您可以傳遞'null'作爲回調數據。請參閱上面的編輯,以便將'SmtpClient.SendAsync()'方法修改爲'async' /'await'模式 –

+0

我之前沒有注意到,但事實上'SmtpClient中有'任務'兼容的發送方法':['SendMailAsync()'](https://msdn.microsoft.com/en-us/library/hh193922(v = vs.110).aspx)。我將留下上面的內容,作爲如何將基於事件的異步API調整爲基於Task的方法的一個例子,但實際上在這種情況下,最好使用SendMailAsync()方法。 –