2012-08-30 16 views
10

MVCMailerでASP.NET MVC 3を使用していますが、SendAsyncを使用して電子メールを送信しようとしましたが、実際にはまだ時間がかかります。だから私は怒鳴るようなコードTask.Factory使用しようとしています非同期電子メールを送信する

var task1 = Task.Factory.StartNew(
      state => 
      { 
       var mail = new UserMailer(); 
       var msg = mail.Welcome("My Name", "[email protected]"); 
       msg.SendAsync(); 
      }); 

    task1.Wait(); 

問題があり、MVCMailerはのHttpContextが必要ですが、このタスクの内側に私はのHttpContextヌルました。

どのように非同期電子メールを送信できますか?

答えて

18

これに小さな加え:
これはQueueUserWorkItemバージョンです。ここではいくつかを助ける拡張メソッドです。

using Mvc.Mailer; 
using System.Threading.Tasks; 
public static void SendEmailAsync(this MvcMailMessage msg, HttpContext currContext) 
{ 
     //make this process a little cleaner 
     Task.Factory.StartNew(() => 
     { 
      System.Web.HttpContext.Current = currContext; 
      msg.SendAsync(); 
     }); 
} 

コントローラメソッドからは次のように使用します。

Mailers.UserMailer um = new Mailers.UserMailer(); 
um.SendWelcomeEmail(dataObject).SendEmailAsync(ControllerContext.HttpContext.ApplicationInstance.Context); 
+0

Hey Matt!ありがとう、参考になりました、これは素晴らしいです、それはasyncronously 100%を送信する、私は人々がMVCMailerは疑似非同期の笑だったと言うことを聞いた。ありがとう! – Baconbeastnz

+2

問題ありません!私はこの1つで少しのために机の上に私の頭を叩いていた:) – Matt

+0

@マット、それは素晴らしい作品!ありがとうございます!!! =) –

0

タスクが必要ありません。 SendAsyncは非同期で、別のスレッド自体を使用します。タスクはあなたの郵送を加速しません。

更新: 私は同じ問題を解決するときに私はタスクと同期送信を使用します。 SendAsyncはそれほど非同期ではないようです。それは私のコードのサンプル(それはのHttpContextを望んでいません)です。

public void SendMailCollection(IEnumerable<Tuple<string, string, MailAddress>> mailParams) 
    { 
     var smtpClient = new SmtpClient 
     { 
      Credentials = new NetworkCredential(_configurationService.SmtpUser, _configurationService.SmtpPassword), 
      Host = _configurationService.SmtpHost, 
      Port = _configurationService.SmtpPort.Value 
     }; 

     var task = new Task(() => 
           { 
            foreach (MailMessage message in mailParams.Select(FormMessage)) 
            { 
             smtpClient.Send(message); 
            } 

           }); 
     task.Start(); 
    } 

    private MailMessage FormMessage(Tuple<string, string, MailAddress> firstMail) 
    { 
     var message = new MailMessage 
      { 
       From = new MailAddress(_configurationService.SmtpSenderEmail, _configurationService.SmtpSenderName), 
       Subject = firstMail.Item1, 
       Body = firstMail.Item2 
      }; 
     message.To.Add(firstMail.Item3); 
     return message; 
    } 
+0

なぜそれが長くなるのですか?私はバックグラウンドで電子メールを送る必要があります。 –

+0

非同期は高速ではありません。これは、遅いプロセスが基本スレッドをブロックしないことを意味し、アプリケーションはユーザーの操作に反応します。 –

+0

確かに、電子メールを送信すると、プロセスはこのタスクによってブロックされます。 –

4

Task.Factory.StartNewは、新しいスレッドを作成します。
は、あなたがこれをしなければならないメインスレッドであるのHttpContextにアクセスする場合:

var task1 = Task.Factory.StartNew(() => 
    { 
    System.Web.HttpContext.Current = ControllerContext.HttpContext.ApplicationInstance.Context; 
    var mail = new UserMailer(); 
    var msg = mail.Welcome("My Name", "[email protected]"); 
    msg.SendAsync(); 
    }); 

task1.Wait(); 

あり、それはTPLまたはQueueUserWorkItemを使用することをお勧めします場合は、長い議論。
誰かがissueに対処しようとしました。

public class HomeController : Controller 
{ 
    private AutoResetEvent s_reset = new AutoResetEvent(false); 

    public ActionResult Index() 
    { 
     var state = new WorkerState() { HttpContextReference = System.Web.HttpContext.Current }; 
     ThreadPool.QueueUserWorkItem(new WaitCallback(EmaiSenderWorker), state); 

     try 
     { 
     s_reset.WaitOne(); 
     } 
     finally 
     { 
     s_reset.Close(); 
     } 

     return View(); 
    } 

    void EmaiSenderWorker(object state) 
    { 
     var mystate = state as WorkerState; 

     if (mystate != null && mystate.HttpContextReference != null) 
     { 
     System.Web.HttpContext.Current = mystate.HttpContextReference; 
     } 

     var mail = new UserMailer(); 
     var msg = mail.Welcome(); 
     msg.SendAsync(); 

     s_reset.Set(); 
    } 

    private class WorkerState 
    { 
     public HttpContext HttpContextReference { get; set; } 
    } 

} 
+0

はいLeflyX!私はすでにこれを試みましたが、MVCMailerオブジェクトにコンテキスト変数を渡すことが可能かどうかはわかりません。 –

+1

@MichelAndrade:私は自分の答えを更新しました。それが役立つかどうか試してみてください。 – LeftyX

+0

LeflyX、ほぼそこに、もし私が "task1.Wait();"それは動作しません –

0
public class UserMailer : MailerBase  
{ 
    RegisterService Service = new RegisterService(); 
    HttpContext Context; 
    public UserMailer(HttpContext context) 
    { 
     Context = context; 
     MasterName="_Layout"; 
    } 

    public void ConfirmRegistration(Register model) 
    { 
     SendAsync(() => 
     { 
      model.Conference = Service.Context.Conferences.Find(model.ConferenceID); // load conference bcs it fails to lazy load automatically. 
      ViewData.Model = model; 
      return Populate(x => 
      { 
       x.Subject = "You registered for " + model.Conference.Name + "!"; ; 
       x.ViewName = "Confirm"; 
       x.To.Add(model.Email); 
      }); 
     }); 
    } 

    private void SendAsync(Func<MvcMailMessage> GetEmail) 
    { 
     Task.Factory.StartNew(() => 
     { 
      System.Web.HttpContext.Current = Context; 
      GetEmail().Send(); 
     }); 
    } 
+2

回答を投稿していただきありがとうございます!コードスニペットは質問に答えることができますが、説明などのようにいくつかの追加情報を追加することはまだ素晴らしいです。 – j0k

関連する問題