Установить фоновый процесс и позволить пользователю продолжить без ожидания - PullRequest
0 голосов
/ 11 октября 2009

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

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

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

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

Есть мысли о том, как лучше всего этого добиться?

Спасибо за вашу помощь, Рич

if (Page.IsPostBack)
    {
        if (JustMeButton.Checked)
        {
            SendMail("emailme@address", 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("admin@address", "Error sending <br><br>" + e.Error.Message);
    }
    else
    {
        SendMail("admin@address", "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("from@address");
    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;
    }
}

Ответы [ 5 ]

2 голосов
/ 11 октября 2009

Я сделал именно это, отправив информационный бюллетень с BeerHouse в новой версии. Вы можете получить книгу сейчас, и исходный код находится на CodePlex, http://thebeerhouse.codeplex.com/ http://professionalaspnet.com/archive/2009/10/07/ASP.NET-3.5-Problem-1320-Design-2D00-Solution.aspx альтернативный текст http://Professionalaspnet.com/images/187586-fg0705.jpg

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

1 голос
/ 11 октября 2009

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

0 голосов
/ 09 апреля 2013

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

0 голосов
/ 11 октября 2009

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

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

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

0 голосов
/ 11 октября 2009

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

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

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

...