So I am trying to send email as notification to user and I want it to run asynchronously
. Initially I implemented with Task.Factory.StartNew
as below:
Task.Factory.StartNew(() => { _notify.NotifyUser(params); });
NotifyUser
is a void method
which actually sends email to the user.
But it was never executing the method. I have placed a log message
inside NotifyUser
method, which was never getting logged.
I followed this post
and came to know that
Sometimes this kind of behaviour is an indication of an overloaded ThreadPool. Seeing as these are long running/blocking tasks, they should not be scheduled to run in the ThreadPool, which is where Task.Factory.StartNew will be sending them using the default TaskScheduler
and so I followed what was suggested there which is as below:
ThreadStart action=()=>{
_notify.NotifyUser(params);
};
Thread thread=new Thread(action){IsBackground=true};
thread.Start();
Found no luck with the above approach too. Again I followed one more approach which even did not work.
Task task = new Task(() => {
_notify.NotifyUser(params);
});
task.RunSynchronously(); //or task.Start();
Is there any other way I can run this task of sending email? I've heard about async await
but I read that it will not be used on void methods
. Can someone let me know what would be the best approach here?
Update
ThreadPool.QueueUserWorkItem(t =>
{
_notify.NotifyUser(params);
});
so that it will execute this method when the thread is available. But still no luck here.
Actual Code
[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);
}
}
}
You should never use StartNew
unless you're doing dynamic task-based parallelism. I explain why on my blog in excruciating detail.
Assuming that you're running on ASP.NET, you should use HostingEnvironment.QueueBackgroundWorkItem
. I suspect that you're seeing an exception from your delegate, and QBWI will log any exceptions to the event log.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With