2011-09-01 14 views
86

SmtpClientを使い捨てにできるようになったので、特にSendAsyncを使用して呼び出しを行うと、管理が少し難解です。おそらく、SendAsyncが完了するまでDisposeを呼び出すべきではありません。しかし、私はそれを呼び出すべきかどうか(例えば、 "使用する"を使用して)。このシナリオは、通話が行われると定期的に電子メールを送信するWCFサービスです。計算の大半は高速ですが、電子メールの送信には1秒ほどかかる場合がありますので、非同期が望ましいでしょう。SmtpClient、SendAsync、Disposeを.NET 4.0で使用するためのベストプラクティス

メールを送信するたびに新しいSmtpClientを作成する必要がありますか?私はWCF全体のために1つ作成する必要がありますか?助けて!

更新場合によっては、それぞれの電子メールが常にユーザーに合わせてカスタマイズされます。 WCFはAzureでホストされ、Gmailはメーラーとして使用されます。

+1

処理する方法の全体像については、この記事を参照してくださいIDisposableをし、非同期:http://stackoverflow.com/questions/974945/how-to-dispose-objects-having-asynchronous-methods -called –

答えて

107

注:.NET 4.5 SmtpClientがasync awaitable方法SendMailAsyncを実装します。下位バージョンの場合は、下記のようにSendAsyncを使用してください。


できるだけ早く、IDisposableインスタンスを廃棄してください。非同期呼び出しの場合、これはメッセージが送信された後のコールバックにあります。

var message = new MailMessage("from", "to", "subject", "body")) 
var client = new SmtpClient("host"); 
client.SendCompleted += (s, e) => { 
          client.Dispose(); 
          message.Dispose(); 
         }; 
client.SendAsync(message, null); 

SendAsyncはコールバックを受け付けません。

+0

最後の行に「await」はありませんか? – niico

+15

'await'が利用可能になる前に、このコードは書かれていませんでした。これは、イベントハンドラを使用した伝統的なコールバックです。新しい 'SendMailAsync'を使用する場合は、' await'を使用するべきです。 – TheCodeKing

+1

SmtpException:メールの送信に失敗しました。 - > System.InvalidOperationException:この時点で非同期操作を開始できません。非同期操作は、非同期ハンドラまたはモジュール内、またはページライフサイクルの特定のイベント中にのみ開始できます。ページの実行中にこの例外が発生した場合は、そのページに<%@ Page Async = "true"%>とマークされていることを確認してください。この例外は、ASP.NET要求処理では一般的にサポートされていない「非同期void」メソッドの呼び出しを示す可能性があります。代わりに、非同期メソッドはTaskを返す必要があり、呼び出し元はそれを待つ必要があります。 – Mrchief

12

一般に、IDisposableオブジェクトはできるだけ早く処理する必要があります。 IDisposableをオブジェクトに実装することは、問題のクラスが確定的にリリースされるべき高価なリソースを保持しているという事実を伝えることを意図しています。しかし、これらのリソースを作成するのはコストがかかり、これらのオブジェクトをたくさん作成する必要がある場合、メモリ内に1つのインスタンスを保持して再利用するほうがパフォーマンスが向上します。違いがあるかどうかを知るための唯一の方法はあります:それをプロファイルしてください!

Re:disposingとAsync:明らかにusingは使用できません。代わりに、一般的にSendCompletedイベントでオブジェクトを配置:

var smtpClient = new SmtpClient(); 
smtpClient.SendCompleted += (s, e) => smtpClient.Dispose(); 
smtpClient.SendAsync(...); 
128

元の質問は.NET 4のために求められましたが、.NET 4.5のように役立つ場合は、SmtpClientは非同期で実行可能なメソッド SendMailAsyncを実装しています。

その結果、非同期でメールを送信するためには、次の通りである:

public async Task SendEmail(string toEmailAddress, string emailSubject, string emailMessage) 
{ 
    using (var message = new MailMessage()) 
    { 
     message.To.Add(toEmailAddress); 

     message.Subject = emailSubject; 
     message.Body = emailMessage; 

     using (var smtpClient = new SmtpClient()) 
     { 
      await smtpClient.SendMailAsync(message); 
     } 
    } 
} 

それは、SendAsyncメソッドを使用して避ける方が良いでしょう。

+0

なぜそれを避ける方が良いですか?私はそれが要件に依存すると思う。 – Jowen

+10

SendMailAsync()は、とにかくSendAsync()メソッドのラッパーです。 async/awaitは、より洗練された方法です。まったく同じ要件を達成します。 –

+0

@BorisLipschitz SendAsyncのようにSendMailAsyncのコールバックメソッドに値を渡す方法はありますか? UserStateのタイプはTaskCompletionSource です。 –

5

オク、古い質問私は知っています。しかし、似たようなものを実装する必要があるとき、私は自分自身を見つけました。私はちょうどいくつかのコードを共有したい。

私はいくつかのメールを非同期に送信するためにいくつかのSmtpClientを繰り返しています。私のソリューションはTheCodeKingに似ていますが、私は代わりにコールバックオブジェクトを処分しています。私はまたSendCompletedイベントでそれを取得するために、私は同様にdisposeを呼び出すことができるようにUserTokenとしてMailMessageを渡しています。このように:

foreach (Customer customer in Customers) 
{ 
    SmtpClient smtpClient = new SmtpClient(); //SmtpClient configuration out of this scope 
    MailMessage message = new MailMessage(); //MailMessage configuration out of this scope 

    smtpClient.SendCompleted += (s, e) => 
    { 
     SmtpClient callbackClient = s as SmtpClient; 
     MailMessage callbackMailMessage = e.UserState as MailMessage; 
     callbackClient.Dispose(); 
     callbackMailMessage.Dispose(); 
    }; 

    smtpClient.SendAsync(message, message); 
} 
+1

送信する電子メールごとに新しいSmtpClientを作成するのがベストプラクティスですか? –

+1

はい、非同期送信の場合、コールバックでクライアントを廃棄する限り... – jmelhus

+1

ありがとう!簡単な説明のためだけです:www.codefrenzy.net/2012/01/30/how-asynchronous-is-smtpclient-sendasync –

4

次のコメントでSmtpClientを処分することが特に重要である理由あなたが見ることができます:クライアントを配置せずにGmailのを使用して複数のメールを送信する私のシナリオでは

public class SmtpClient : IDisposable 
    // Summary: 
    //  Sends a QUIT message to the SMTP server, gracefully ends the TCP connection, 
    //  and releases all resources used by the current instance of the System.Net.Mail.SmtpClient 
    //  class. 
    public void Dispose(); 

、私がするために使用しました取得:

メッセージ:サービスは利用できません。送信チャネルを閉じます。 サーバーの応答は4.7.0一時的なシステムの問題でした。後でもう一度試してください (WS)。 oo3sm17830090pdb.64 - gsmtp

+0

これまでの処理をしなくてもSMTPクライアントを送信していたので、ここで例外を共有してくれてありがとう。私は自分のSMTPサーバーを使用していますが、良いプログラミング方法は常に考慮する必要があります。あなたのエラーを見て、私は現在注意を喚起しており、プラットフォームの信頼性を保証するために関数を処理するようにコードを修正する予定です。 – vibs2006

関連する問題