2016-05-05 39 views
5

Così sto cercando di inviare e-mail come notifica all'utente e voglio che venga eseguito asynchronously. Inizialmente ho implementato con Task.Factory.StartNew come di seguito:Attività o Thread non funzionanti/in esecuzione quando sono ospitati sul server

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

NotifyUser è un void method che in realtà invia e-mail all'utente.

Ma non è mai stato in esecuzione il metodo. Ho inserito un log message all'interno del metodo NotifyUser, che non è mai stato registrato.

ho seguito this post ed è venuto a sapere che

A volte questo tipo di comportamento è indice di un ThreadPool sovraccarico. Visto che questi sono lunghi da corsa/compiti di blocco, non dovrebbero essere programmati per l'esecuzione in ThreadPool, che è dove Task.Factory.StartNew sarà l'invio utilizzando il default TaskScheduler

e così ho seguito quello che è stato suggerito c'è qui sotto:

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

Non ho trovato fortuna con l'approccio di cui sopra. Di nuovo ho seguito un altro approccio che non ha funzionato.

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

Esiste un altro modo per eseguire questa attività di invio di posta elettronica? Ho sentito parlare di async await ma ho letto che non verrà utilizzato su void methods. Qualcuno può farmi sapere quale sarebbe l'approccio migliore qui?


Aggiorna

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

modo che possa eseguire questo metodo quando il filo è disponibile. Ma ancora senza fortuna qui.

codice vero e proprio

[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

Dove è il codice che ci hai mostrato nel tuo progetto? È all'interno del metodo di azione del controller o da qualche altra parte? – Fabjan

+0

@Fabjan .. Sì .. È nel metodo di azione del controllore. –

+0

Prima di tutto cambia il tag 'C# 4.0' in * .NET Framework * 4.0 perché è confuso. Ho rimosso la mia risposta perché in .NET 4.0 non è possibile usare 'async await' o' Task.Run() '(entrambi introdotti nella versione 4.5) Su .NET 4.0 sembra che tu abbia provato tutte le opzioni a cui posso pensare. La chiamata su Task.Factory.StartNew() 'dovrebbe essere sufficiente per avviare una nuova attività presumendo che ci siano alcuni * thread disponibili * in un pool di thread. – Fabjan

risposta

1

You should never use StartNew unless you're doing dynamic task-based parallelism. Spiego perché sul mio blog in dettaglio straziante.

Supponendo che si esegua su ASP.NET, è necessario utilizzare HostingEnvironment.QueueBackgroundWorkItem. Sospetto che tu stia vedendo un'eccezione dal tuo delegato e QBWI registrerà eventuali eccezioni nel registro eventi.

+0

Stephen .. Sicuramente proverò questo n ti faccio sapere se sono in grado di ottenere quello che intendo .. –

+0

Qual è lo spazio dei nomi per questo 'HostingEnvironment.QueuBackgroundWorkItem' .. Ho usato 'System.Web.Hosting' ma non mostrava' QueueBackgroundWorkItem' sotto di esso .. –

+0

E 'stato introdotto solo in .Net Framework 4.5.2 ([link a msdn] (https://msdn.microsoft.com/en -us/library/dn636893 (v = vs.110) aspx)) – Fabjan