10

ASP.NET MVC 3をMVCMailerで使用していますが、SendAsyncを使用して電子メールを送信しようとしましたが、実際にはさらに時間がかかります。

だから私は次のコードのようにTask.Factoryを使おうとしています:

   var task1 = Task.Factory.StartNew(
            state =>
            {
                var mail = new UserMailer();
                var msg = mail.Welcome("My Name", "myemail@gmail.com");
                msg.SendAsync(); 
            });

   task1.Wait();

問題は、MVCMailerにはHttpContextが必要ですが、このタスク内でHttpContextNullを取得しました。

非同期電子メールを送信するにはどうすればよいですか?

4

4 に答える 4

19

これへの小さな追加。これがいくつかを助けるための拡張メソッドです。

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);
于 2013-03-03T04:07:00.213 に答える
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", "myemail@gmail.com");
    msg.SendAsync();
    });

task1.Wait();

TPLまたはQueueUserWorkItemを使用する方がよいかどうかについては長い議論があります。誰かがこの問題
に対処しようとしました。 これはQueueUserWorkItemのバージョンです。

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

}
于 2012-08-30T21:44:26.560 に答える
0

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

更新:同じ問題を解決するとき、タスクと同期送信を使用します。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;
    }
于 2012-08-30T16:51:10.027 に答える
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();
        });
    }
于 2012-10-06T09:40:45.917 に答える