2009-10-11 3 views
0

J'ai un outil de newsletter que j'essaye de configurer pour fonctionner comme un processus d'arrière-plan pour envoyer les emails. Le code ci-dessous fonctionne sans aucun problème mais le problème que j'ai est qu'il est lent.Définir un processus d'arrière-plan et permettre à l'utilisateur de continuer sans attendre

S'il y a 50 courriels à envoyer, cela peut être très lent pour l'utilisateur final car il doit regarder l'écran jusqu'à 1 min 30sec. Cela devient un plus gros problème pour moi si le client envoie un courriel à un plus grand groupe de personnes. La raison pour laquelle j'envoie chaque mail individuellement à l'envoi de 1 et à la liste de diffusion est que chaque email contient un contenu spécifique pour chaque utilisateur - comme des codes de lien de désabonnement, un nom de personne au début du mail, etc.

Je cherche une solution où je peux laisser l'utilisateur cliquer sur un bouton et avoir .net exécuter la partie d'email d'envoi en arrière-plan pendant que l'utilisateur final est amené à une page indiquant que leur email est envoyé . Idéalement, cela ne devrait pas prendre plus de temps qu'un postback régulier pour que tout cela se produise - pas les quelques minutes actuelles.

Des idées sur la meilleure façon d'y parvenir?

Merci pour votre aide, Rich

if (Page.IsPostBack) 
    { 
     if (JustMeButton.Checked) 
     { 
      SendMail("[email protected]", EmailTemplate); 
     } 
     if (EveryoneButton.Checked) 
     { 
      //setup background process 
      BackgroundWorker bw = new BackgroundWorker(); 
      bw.WorkerReportsProgress = false; 
      bw.WorkerSupportsCancellation = false; 
      bw.DoWork += new DoWorkEventHandler(bw_DoWork); 
      bw.RunWorkerCompleted += new RunWorkerCompletedEventHandler(bw_RunWorkerCompleted); 
      bw.RunWorkerAsync(); 

      //bring user to next screen and display message 
      Response.Redirect("emailSendingMessageScreen.aspx"); 
     } 
    } 

private void bw_DoWork(object sender, DoWorkEventArgs e) 
{ 
    DataTable emailTable = (DataTable)Session["emailTable"]; 
    foreach (DataRow row in emailTable.Rows) 
    { 
     SendMail(row["email"], row["name"], EmailTemplate); 
    } 
} 
private void bw_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e) 
{ 
    if (!(e.Error == null)) 
    { 
     SendMail("[email protected]", "Error sending <br><br>" + e.Error.Message); 
    } 
    else 
    { 
     SendMail("[email protected]", "emails sent successfully."); 
    } 
    //clear out the sessions created for sending this email 
    Session.Remove("emailTable"); 
} 

private void SendMail(string email, string emailMessage) 
{ 
    MailMessage mailMessage = new MailMessage(); 
    mailMessage.From = new MailAddress("[email protected]"); 
    mailMessage.To.Add(new MailAddress(email)); 
    mailMessage.Subject = Server.HtmlEncode(EmailSubject.Text.Trim()); 
    mailMessage.Body = emailMessage; 
    mailMessage.IsBodyHtml = true; 

    SmtpClient smtpClient = new SmtpClient(); 

    Object userState = mailMessage; 

    smtpClient.SendCompleted += new SendCompletedEventHandler(smtpClient_SendCompleted); 
    smtpClient.Timeout = 10000; 

    try 
    { 
     smtpClient.SendAsync(mailMessage, userState); 
    } 
    catch (SmtpException smtpExc) 
    { 
     MailMessageTxt.Text += "Error Code: " + smtpExc.StatusCode; 
     MailMessageTxt.Visible = true; 
    } 
    catch (Exception ex) 
    { 
     MailMessageTxt.Text += "Error is: " + ex; 
     MailMessageTxt.Visible = true; 
    } 
} 

void smtpClient_SendCompleted(object sender, System.ComponentModel.AsyncCompletedEventArgs e) 
{ 
    MailMessage mailMessage = e.UserState as MailMessage; 

    if (e.Error != null) 
    { 
     MailMessageTxt.Text = "Error occured, info=" + e.Error.Message; 
     MailMessageTxt.Visible = true; 
    } 
} 

Répondre

2

J'ai fait cette chose en envoyant une newsletter avec la BeerHouse dans la nouvelle version.Vous pouvez obtenir le livre maintenant et le code source est sur CodePlex, http://thebeerhouse.codeplex.com/ http://professionalaspnet.com/archive/2009/10/07/ASP.NET-3.5-Problem-1320-Design-2D00-Solution.aspx alt text http://Professionalaspnet.com/images/187586-fg0705.jpg

La solution utilise AJAX pour envoyer les e-mails et permet à l'utilisateur de continuer à naviguer sur le site sans se soucier de la lettre d'information étant envoyé. Quand cela est fait, il prend soin de lui-même et l'utilisateur peut vérifier comme ils veulent. Son chapitre 7 dans le livre, profitez.

+0

Bon exemple. Merci Chris :) –

0

Déplacer tout le travail d'envoi du courrier électronique à la classe séparée et l'exécuter en utilisant ThreadPool

MailSender sender = new MailSender(parameters. ....); 
ThreadPool.EnqueueUserItem(sender.sendAllEmails) 

Utiliser travailleur de fond ne fonctionnera pas. Il sera éliminé quand il sortira du contexte, ce qui signifie sur Response.End

1

Un thread créé dans une page ASP sera tué si le processus de travail ASP est recyclé pour une raison quelconque. Un service Windows qui exécute la tâche via une file d'attente de messages est idéal pour les tâches longues. Une autre solution consiste à utiliser l'expiration du cache, expliqué ici: http://www.codeproject.com/KB/aspnet/ASPNETService.aspx

0

J'ai trouvé que faire des tâches comme celle-ci dans le processus ASP.NET est problématique car vous ne pouvez pas garantir que le processus se terminera ou aura du succès. Si le processus est interrompu, vous n'avez aucun rétablissement. Je voudrais d'abord enregistrer tous vos e-mails dans une base de données, puis disposer d'un service qui interroge les nouvelles entrées dans cette base de données ou table qui traite l'envoi réel des e-mails. L'avantage à cela est que si votre fournisseur de messagerie ou processus ASP.NET tombe en panne vous ne perdez aucun email et vous avez un historique de tous les emails envoyés avec leurs détails de quand, qui, etc ... Vous Vous pouvez également extraire ou modifier l'e-mailer pour en faire plus, comme envoyer à Twitter ou à un message texte, etc. Ceci déconnecte efficacement vos notifications de votre application.

Toutes les applications que j'ai créées récemment utilisent ce type de modèle et ont empêché la perte de messages électroniques en raison de pannes de service et d'autres raisons. Il a également permis de consulter tous les emails passés dans le système et d'obtenir des métriques me permettant d'optimiser le besoin d'envoyer des mails en stockant des informations supplémentaires dans le mail comme raison envoyée, si c'est pour signaler une erreur, etc. .. Ajout sur des ajouts tels que les notifications de routage (par exemple aller à un message texte à la place si l'email) en fonction de l'heure de la journée ou de l'utilisateur a été possible sans modifications à l'application primaire.

+0

Salut Kelsey, cela semble être une meilleure solution que ce que j'essaie de faire ici. Si vous envoyez à 1000 des utilisateurs comment économisez-vous efficacement des milliers d'enregistrements dans votre base de données? boucle à travers et stocker chacun ou insert en vrac? À votre santé. –

+0

Je les ai fait par lots en passant XML to SQL. Faites comme 100 ou plus à la fois pour les insérer et faites ensuite traiter votre processus par lots. Assurez-vous de ne pas mettre à jour le bit envoyé (ou tout ce que vous utilisez pour marquer l'e-mail) jusqu'à ce qu'il réussisse. Envoyer 2 emails est préférable à aucun dans la plupart des cas :) – Kelsey

0

Il suffit d'utiliser ajax pour exécuter le processus. L'utilisateur continue son activité pendant que le serveur se charge du fardeau.

Questions connexes