所以我正在尝试将电子邮件作为通知发送给用户,我希望它运行asynchronously
。最初,我使用Task.Factory.StartNew
实现如下:
Task.Factory.StartNew(() => { _notify.NotifyUser(params); });
NotifyUser
是实际向用户发送电子邮件的void method
。
但它从未执行过该方法。我在NotifyUser
方法中放置了一个log message
,它从未被记录。
我跟踪this post
并了解
有时,这种行为表明ThreadPool过载。由于这些任务是长时间运行/阻塞的任务,因此不应将它们安排在ThreadPool中运行,ThreadPool就是Task所在的位置。工厂StartNew将使用默认的TaskScheduler 发送它们
所以我遵循了下面的建议:
ThreadStart action=()=>{
_notify.NotifyUser(params);
};
Thread thread=new Thread(action){IsBackground=true};
thread.Start();
上面的方法也没有运气。我又一次采取了一种甚至没有奏效的方法。
Task task = new Task(() => {
_notify.NotifyUser(params);
});
task.RunSynchronously(); //or task.Start();
有没有其他方法可以让我执行发送电子邮件的任务?我听说过async await
,但我读到它不会在void methods
上使用。有人能告诉我什么是最好的方法吗?
更新
ThreadPool.QueueUserWorkItem(t =>
{
_notify.NotifyUser(params);
});
以便在线程可用时执行该方法。但在这里仍然没有运气。
实际代码
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult AddEditUser(UVModel model)
{
if (HasPermission())
{
string message = string.Empty;
bool success = false;
string returnUrl = string.Empty;
if (ModelState.IsValid)
{
using (_db = new EFDB())
{
//fill user model
_db.Entry(user).State = state;
_db.SaveChanges();
_notify = new SendNotification();
_notify.NotifyUser(params); //This has to be asynchronous
success = true;
returnUrl = Url.Action("Action", "Controller", null, HttpContext.Request.Url.Scheme, HttpContext.Request.Url.Host);
message="success";
}
}
else
message = "Server side validation failed!";
return Json(new { result = success, message = message, redirectUrl = returnUrl }, JsonRequestBehavior.AllowGet);
}
else
return Json(new { result = false, message = "You do not have permission to perform this action!", redirectUrl = "" }, JsonRequestBehavior.AllowGet);
}
SendNotification.cs
public void NotifyUser(Parameter params)
{
using (MailMessage mail = new MailMessage())
{
_db = new EFDB();
mail.To.Add(params.toAddress);
mail.From = params.from;
mail.Subject = params.subject;
mail.Body = params.body;
mail.IsBodyHtml = true;
mail.Priority = MailPriority.High;
SmtpClient smtp = new SmtpClient();
smtp.Host = "some smtp host";
smtp.Port = 25;
smtp.UseDefaultCredentials = false;
smtp.EnableSsl = false;
smtp.Credentials = new NetworkCredential("uname", "pwd");
smtp.DeliveryMethod = SmtpDeliveryMethod.Network;
try
{
smtp.Send(mail);
}
catch (SmtpFailedRecipientException se)
{
LogError.LogMessage("SmtpFailedRecipientException Exception - " + se.Message.ToString(), context);
}
catch (SmtpException se)
{
LogError.LogMessage("SmtpException - " + se.Message.ToString(), context);
}
}
}
除非您在执行基于任务的动态并行,否则永远不应该使用StartNew
。我在博客上详细解释了原因。
假设您在ASP上运行。NET,您应该使用HostingEnvironment.QueueBackgroundWorkItem
。我怀疑您看到了来自代理的异常,QBWI会将任何异常记录到事件日志中。