2016-05-05 40 views
5

Próbuję wysłać wiadomość e-mail jako powiadomienie do użytkownika i chcę, aby działała pod numerem asynchronously. Początkowo realizowane z Task.Factory.StartNew jak poniżej:Zadanie lub wątek nie działa/działa po uruchomieniu na serwerze

Task.Factory.StartNew(() => { _notify.NotifyUser(params); }); 

NotifyUser jest void method które faktycznie wysyła wiadomość e-mail do użytkownika.

Ale nigdy nie wykonywał tej metody. Umieściłem metodę log message wewnątrz NotifyUser, która nigdy nie była rejestrowana.

Śledziłem this post i poznał, że

Czasami tego rodzaju zachowanie jest oznaką przeciążonej puli wątków. Widząc, jak są one długie bieganie/zadania blokujące, nie powinny być zaplanowane w puli wątków, czyli tam, gdzie Task.Factory.StartNew będzie wysyłał je za pomocą domyślnej TaskScheduler

a więc po co sugerowano tam, który jest jak poniżej:

ThreadStart action=()=>{ 
    _notify.NotifyUser(params); 
}; 
Thread thread=new Thread(action){IsBackground=true}; 
thread.Start(); 

Nie znalazłem też szczęścia w powyższym podejściu. Znowu podążyłem za jeszcze jednym podejściem, które nawet nie zadziałało.

Task task = new Task(() => { 
    _notify.NotifyUser(params); 
}); 
task.RunSynchronously(); //or task.Start(); 

Czy istnieje jakikolwiek inny sposób na wykonanie tego zadania związanego z wysyłaniem wiadomości e-mail? Słyszałem o async await, ale czytałem, że nie będzie on używany na void methods. Czy ktoś może mi powiedzieć, jakie byłoby najlepsze podejście?


Aktualizacja

ThreadPool.QueueUserWorkItem(t => 
{ 
    _notify.NotifyUser(params); 
}); 

tak, że będzie wykonać tę metodę, gdy wątek jest dostępna. Ale wciąż nie ma tu szczęścia.

rzeczywisty kod

[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); 
      } 
    } 
} 
+2

Gdzie jest kod, który pokazałeś nam w swoim projekcie? Czy jest w środku metody działania kontrolera, czy gdzieś indziej? – Fabjan

+0

@Fabjan .. Tak .. Jest to metoda działania kontrolera. –

+0

Po pierwsze zmień tag "C# 4.0" na * .NET Framework * 4.0, ponieważ jest to mylące. Usunąłem moją odpowiedź, ponieważ w .NET 4.0 nie można użyć 'async await' lub' Task.Run() '(oba wprowadzone w wersji 4.5). Na .NET 4.0 wydajesz się wypróbować wszystkie opcje, które mogę wymyślić. Wywołanie w 'Task.Factory.Funkcja StartNew() 'powinna wystarczyć do rozpoczęcia nowego zadania, zakładając, że istnieje kilka * dostępnych wątków * w puli wątków. – Fabjan

Odpowiedz

1

You should never use StartNew unless you're doing dynamic task-based parallelism. Wyjaśniam, dlaczego na moim blogu w rozdzierających szczegółach.

Zakładając, że korzystasz z ASP.NET, powinieneś użyć HostingEnvironment.QueueBackgroundWorkItem. Podejrzewam, że widzisz wyjątek od swojego delegata, a QBWI zarejestruje wszystkie wyjątki w dzienniku zdarzeń.

+0

Stephen .. Zdecydowanie spróbuję tego, niech ci wiadomo, czy jestem w stanie osiągnąć to, co zamierzam. –

+0

Co to jest przestrzeń nazw dla tego 'HostingEnvironment.QueuBackgroundWorkItem' .. Użyłem 'System.Web.Hosting', ale jego nie pokazuje' QueueBackgroundWorkItem' pod nim .. –

+0

Został wprowadzony tylko w .Net Framework 4.5.2 ([link do msdn] (https://msdn.microsoft.com/pl -us/library/dn636893 (v = vs.110) .aspx)) – Fabjan