发送异步电子邮件
我在MVCMailer中使用ASP.NET MVC 3,我尝试使用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,但在这个任务中我得到了HttpContext Null。
如何发送Async电子邮件?
这是一个小小的补充。 这是一个帮助一些的扩展方法。
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);
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; } } }
你不需要任务。 SendAsync是异步的,并使用另一个自我线程。 任务不会加速你的邮寄。
更新 :当我解决相同的问题时,我使用任务和同步发送。 似乎SendAsync不是那么异乎寻常。 它是我的代码示例(它不想要HttpContext):
public void SendMailCollection(IEnumerable> 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 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; }
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 GetEmail) { Task.Factory.StartNew(() => { System.Web.HttpContext.Current = Context; GetEmail().Send(); }); }