2012-02-09 5 views
0

私は非同期で電子メールメッセージを送信しようとしていますが、スレッドプールまたは単純なスレッド内からSendMailMesage()メソッドを呼び出すとメールは送信されません。スレッドプールから呼び出されたときにGmailメールが送信されない

これを達成する方法はありますか? sendindを定期的に電子メールで送信すると、アプリケーションが大幅に遅くなります。

PS:重要な場合は、参照プロジェクトからSendMailMesage()を送信していますが、MVCプロジェクト自体からは送信していません。

ありがとうございました。

編集:マイコード。

namespace App.Core.Utils.Mailer 
{ 
    public static class Sender 
    { 
     /// <summary> 
     /// Sends a MailMessage object using the SMTP settings. 
     /// </summary> 
     public static void SendMailMessage(MailMessage message) 
     { 
      if (!Settings.Instance.SendEmails) 
      { 
       return; 
      } 

      if (message == null) 
       throw new ArgumentNullException("message"); 

      try 
      { 
       message.IsBodyHtml = true; 
       message.BodyEncoding = Encoding.UTF8; 
       var smtp = new SmtpClient(Settings.Instance.SmtpServer); 

       // don't send credentials if a server doesn't require it, 
       // linux smtp servers don't like that 
       if (!string.IsNullOrEmpty(Settings.Instance.SmtpUserName)) 
       { 
        smtp.Credentials = new System.Net.NetworkCredential(Settings.Instance.SmtpUserName, Settings.Instance.SmtpPassword); 
       } 
       smtp.Port = Settings.Instance.SmtpServerPort; 
       smtp.EnableSsl = Settings.Instance.EnableSsl; 
       smtp.Send(message); 
      } 
      catch (SmtpException) 
      { 
       //OnEmailFailed(message); 
      } 
      finally 
      { 
       // Remove the pointer to the message object so the GC can close the thread. 
       message.Dispose(); 
      } 
     } 

     public static void SendMailMessageAsync(MailMessage message) 
     { 
      ThreadPool.QueueUserWorkItem(state => SendMailMessage(message)); 
     } 
    } 
} 

注記:これはWebフォームで機能します。コードをMVCプロジェクトにコピーしましたが、SendMailMessageAsyncメソッドを呼び出すと何も送信されません。エラーもありません。

+0

スレッドプールで呼び出されていないときに機能しますか? – casperOne

答えて

1

MVCでこれを使用しています。それはインターフェイスを実装しているので、あなたの代わりに静的メソッドを使用してのコントローラのコンストラクタにインスタンスを注入することができます

public class MvcEmailSender : ISendEmails 
{ 
    public MvcEmailSender(ILogExceptions logger, 
     IQueryEntities queryables, IUnitOfWork unitOfWork) 
    { 
     // save args to readonly fields on the instance 
    } 

    public void Send(EmailMessage message) 
    { 
     // constructor really passes more args here 
     var sender = new SmtpEmailSender(message, arg2, arg3, arg4); 
     var thread = new Thread(sender.Send); 
     thread.Start(); 
    } 
} 

public class SmtpEmailSender 
{ 
    private readonly EmailMessage _emailMessage; 
    private int _retryCount; 

    public SmtpEmailSender(EmailMessage emailMessage, ILogExceptions logger, 
     IQueryEntities queryables, IUnitOfWork unitOfWork) 
    { 
     if (emailMessage == null) 
      throw new ArgumentNullException("emailMessage"); 

     _emailMessage = emailMessage; 
     // save other constructor args to readonly fields 
    } 

    public void Send() 
    { 
     try 
     { 
      // assemble message, send, & update database 
     } 
     catch (Exception ex) 
     { 
      // log exception, then retry like so: 
      if (_retryCount++ <= 3) 
      { 
       Thread.Sleep(10000); 
       Send(); 
      } 
     } 
    } 
} 

我々はまた、web.configファイルで提供されるいくつかの設定ができますか?その場合は、web.configのsystem.netセクションで質問を更新してください。

これを使用するには、コントローラからISendEmails.Send(EmailMessage)を呼び出します。この実装は、MVCに知られていないスレッドを処理します。

これら2つのクラスとISendEmailsインターフェイスは、MVCプロジェクトではなく、参照されたプロジェクトで宣言されています(インターフェイスはAPIアセンブリにあり、上記の2つのクラスはIMPLアセンブリにあります)。

更新

私はコメントに反応して、コードを更新しました。これらのクラスのコンストラクタは、もともと描かれていたより多くの依存関係を持っていることに注意してください。私たち(コンストラクタ)もILogExceptions、IQueryEntities、IUnitOfWorkの依存関係を注入します。 tryブロック内では、EmailMessageをMailMessageに変換して送信するだけでなく、EmailMessageドメインオブジェクトがデータベースで更新され、SmtpClient.Send(MailMessage)が成功した後にSentOnUtc値が更新されます。これは実際に電子メールが送信されたことを証明する方法です。例外がキャッチされると、再試行の前に記録されます。

+0

ありがとう、これは実際に働いた。 Send()メソッドのコメントコードで、どのように手作業で再試行を送信するのか気になりますか? :) – rebelliard

+0

コード+回答が更新されました。 – danludwig

+0

ありがとう。 :) – rebelliard

関連する問題