2009-10-11 2 views
0

У меня есть инструмент для рассылки новостей, который я пытаюсь настроить для работы в качестве фонового процесса для отправки электронной почты. Код ниже работает без каких-либо проблем, но проблема заключается в том, что он медленный.Установите фоновый процесс и позвольте пользователю продолжать, не дожидаясь.

Если есть 50 писем для отправки, это может быть очень медленным для конечного пользователя, поскольку они должны смотреть на экран до 1 минуты 30 секунд. Это становится большой проблемой для меня, если клиент отправляет электронное письмо большей группе людей.

Причина, по которой я отправляю каждую почтовую почтовую почтовую почтовую рассылку отдельно от отправления 1 и списком рассылки электронной почты, заключается в том, что каждое электронное письмо содержит определенный контент для каждого пользователя - например, коды отписки от подписки, личное имя в начале письма и т. Д.

Я ищу решение, в котором я могу позволить пользователю нажимать на кнопку и иметь .net запустить отправку электронной почты в фоновом режиме, в то время как переднего конечного пользователя отображается на страницу с сообщением о том, что отправляется их электронная почта , В идеале, это должно занять не больше, чем регулярная обратная передача для всего, что происходит, а не текущие несколько минут.

Любые мысли о том, как наилучшим образом достичь этого?

Спасибо за вашу помощь, 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; 
    } 
} 

ответ

2

Я сделал это, отправив информационный бюллетень с BeerHouse в новой версии.Вы можете получить книгу сейчас и исходный код на 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

Решения использует AJAX для отправки сообщений электронной почты и позволяет пользователю сохранить осматриваться сайтом, не будучи обеспокоена рассылкой будучи разослал. Когда это делается, он просто заботится о себе, и пользователь может проверить, как они хотят. Его глава 7 в книге, наслаждайтесь.

+0

Отличный пример. Спасибо Крису :) –

0

Move вся работа отправки электронной почты в отдельный класс и запустить его с помощью ThreadPool

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

Использование фона рабочего не будет работать. Он будет удален, если он выходит из контекста, то есть на Response.End

1

Нить, созданная на странице ASP, будет убита, если рабочий процесс ASP будет переработан по какой-либо причине. Служба Windows, которая выполняет задачу через очередь сообщений, идеально подходит для длительных рабочих заданий. Еще одно решение «трюк» - использование срока действия кеша, объясняемое здесь: http://www.codeproject.com/KB/aspnet/ASPNETService.aspx

0

Я нашел попытку выполнить такие задачи в рамках процесса ASP.NET, так как вы не можете гарантировать, что процесс завершится или будет успешным. Если процесс обрезается, у вас нет восстановления. Сначала у меня были бы все ваши электронные письма, сохраненные в БД, а затем служба, которая опросит новые записи в этой базе данных или таблице, которая обрабатывает фактическую отправку писем.

Преимущество этого в том, что если ваш поставщик электронной почты или процесс ASP.NET не работает, вы не теряете никаких писем, и у вас есть история всех отправленных электронной почты с указанием их сведений о том, когда, кто и т. Д. ... также может разорвать или изменить почтовый клиент, чтобы делать больше, например, отправлять в Twitter или текстовое сообщение телефона и т. д. Это эффективно отделяет ваши уведомления от вашего приложения.

Все приложения, которые я недавно использовал, используют этот тип модели, и он потерял электронные письма от потери из-за сбоев службы и других причин. Он также позволил найти все электронные письма, которые прошли через систему, и получить показатели, которые позволяют мне оптимизировать необходимость отправки электронных писем, сохраняя дополнительную информацию в записи электронной почты, например, отправленную причину, если она сообщает об ошибке и т. Д. .. Добавление дополнительных дополнений, таких как уведомления о маршрутизации (например, переход на текстовое сообщение вместо этого, если электронная почта) в зависимости от времени суток или пользователя, возможно без изменений основного приложения.

+0

Привет, Келси, это звучит как лучшее решение, чем то, что я пытаюсь сделать здесь. Если вы отправляете 1000 пользователям, как эффективно сохранить 1000 записей в вашей базе данных? прокручивать и хранить каждую или объемную вставку? Приветствия. –

+0

Я делал их в партиях, передавая XML на SQL. Сделайте примерно 100 или около того за раз, чтобы вставить их, а затем также обработайте их процессом партиями. Убедитесь, что вы не обновили переданный бит (или все, что вы используете для отметки электронной почты), пока оно не будет успешным. Отправка 2 электронных писем предпочтительнее ни одного в большинстве случаев :) – Kelsey

0

Просто используйте ajax для выполнения process.let пользователь продолжит свою деятельность, пока сервер не несет бремени.