2017-04-26 25 views
3

ASP.NET IDに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- in-c-sharp)? –

+0

@AlexeiLevenkov:それは有効なコードではないと言っている例があり、 'SmtpClient.SendAsync()'がコールバックに関連して2番目の引数を取ることがわかりました。それは私が避けたかったものです。 –

+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; 
    } 
} 

あなたは、あなたが代わりにTask.FromResult<bool>(true)を使用することができ、事前4.6土地で立ち往生している場合。

あなたのコメントで約と混乱しています。「async...awaitusingと互換性がありません。です。私の経験では、それはうまく動作します。あなたのメソッドが実際には非同期であった方がずっと良いでしょう。 asyncメソッドを偽造するための最良の構文が何であるかではなく、それを行う方法に焦点を当てることで、より良いサービスになると思います。

補遺:

は、私はまだusingの使用についてあなたの懸念を明確にしていません。しかし、あなたのご意見に基づいて、SmtpClient.SendAsync()を使用したいと思われますが、async/awaitというコンテキストでそれをどのように適用するかは不明です。

残念ながら、async/awaitの前であっても、私たちは.NETで多くの非同期メソッドを使用していました。これらのメソッドでは、新しい待望のメソッドの命名規則と同じ名前が使用されました。 (明白である:それは残念なことに命名したものであり、非同期メソッドが存在していたわけではない:))。ただし、すべての場合において、古いAPIを新しいAPIに適合させることは可能です。

場合によっては、Task.FromAsync()メソッドを使用するのと同じくらい簡単です。これは古いモデルのBegin.../End...をサポートしています。しかし、SmtpClient.SendAsync()モデルは、イベントベースのコールバックアプローチであり、少し異なるアプローチが必要です。

注:SmtpClientクラスには、Taskに準拠した非同期動作のメソッドSendMailAsync()があることに気付きました。実際には、古いSendAsync()メソッドを適用する必要はありません。しかし、Taskベースの代替案が提供されていない場合に、どのようにそのような適応を行うかを示すために有用な例です。

簡単に言うと、オブジェクトのSendCompletedイベントでTaskCompletionSourceを使用できます。上記

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; 
     } 
    } 
} 

非同期操作を開始し、TaskCompletionSource<bool>のための結果を設定する(つまり、ドキュメントが参照する「コールバック」)SendCompletedイベントのハンドラを使用します。ここではそれがどのように見えるかの輪郭があります結果値は実際に使用されることはありませんが、TaskCompletionSource&hellipのプレーンバニラTaskのバージョンはありません; いくつかの値が必要です。

taskSource.Taskオブジェクトを直接返すのではなく、awaitを使用します。これは、電子メール操作が実際に完了したときにSmtpClientオブジェクトの廃棄を正しく処理できるためです。

+0

私は最新のビットを持っています。しかし、私はasychronousメソッドで 'using'ブロックを避けたたくさんの例を見つけました。私はこれをもっと深く考えていますが、 'SmtpClient.SendAsync()'は第2引数を必要とします。これはコールバックの文脈で意味をなさないように見えます。 –

+0

コールバックデータを必要としない場合は、コールバックデータに 'null'を渡すことができます。 'SmtpClient.SendAsync()'メソッドを 'async' /' await'パターンに適合させるための上記の編集方法を参照してください。 –

+0

これまで気付いていませんでしたが、 'SmtpClient ':[' SendMailAsync() '](https://msdn.microsoft.com/en-us/library/hh193922(v = vs.110).aspx)を参照してください。イベントベースの非同期APIを 'Task'ベースに一般的に適用する方法の例として、上記の説明を残しておきますが、この特定のシナリオでは' SendMailAsync() 'メソッドを使用する方が良いでしょう。 –

関連する問題