设置后台进程并允许用户继续而无需等待

时间:2009-10-11 14:50:43

标签: c# asp.net email backgroundworker

我有一个新闻简报工具,我正在尝试将其作为后台进程运行以发送电子邮件。下面的代码没有任何问题,但我遇到的问题是它很慢。

如果要发送50封电子邮件,最终用户可能会非常慢,因为他们必须盯着屏幕最多1分30秒。如果客户端正在向更大的人群发送电子邮件,这对我来说就成了一个更大的问题。

我单独发送每封邮件的原因与发送1和发送电子邮件列表相关的是每封电子邮件包含每个用户的特定内容 - 例如取消订阅链接代码,邮件开头的个人姓名等。

我正在寻找一个解决方案,我可以让用户点击按钮,让.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 个答案:

答案 0 :(得分:2)

我做了这件事,在新版本中发送了啤酒屋的时事通讯。您现在可以获取该书,源代码位于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章,享受。

答案 1 :(得分:1)

如果ASP工作进程因任何原因被回收,那么在ASP页面中创建的线程将被终止。通过消息队列执行任务的Windows服务非常适合长时间运行的作业。另一个“技巧”解决方案是使用缓存过期,在此解释:http://www.codeproject.com/KB/aspnet/ASPNETService.aspx

答案 2 :(得分:0)

将发送电子邮件的所有工作移至单独的类并使用ThreadPool运行

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

使用后台工作程序将无法正常工作。当它脱离上下文时将被处理,这意味着在Response.End

答案 3 :(得分:0)

我发现在ASP.NET进程中尝试执行此类任务是有问题的,因为您无法保证进程将完成或成功。如果这个过程被切断,你就无法恢复。我会先将所有电子邮件保存到数据库中,然后使用一个服务来轮询此数据库或表中处理实际发送电子邮件的新条目。

这样做的好处是,如果您的电子邮件提供商或ASP.NET流程失败,您不会丢失任何电子邮件,并且您有所有电子邮件的历史记录,其中包含详细信息,包括何时,谁等...您可以也可以撕掉或更改电子邮件以执行更多操作,例如发送到Twitter或手机短信等。这有效地将您的通知与应用程序分离。

我最近制作的所有应用程序都使用这种类型的模型,它已经阻止了电子邮件因服务失败和其他原因而丢失。它还可以查找已经通过系统的所有电子邮件,并获得指标,通过在电子邮件记录中存储额外信息(如发送原因,如果要报告错误等),我可以优化发送电子邮件的需求。 ..添加诸如路由通知之类的附加信息(例如,如果是电子邮件则转到文本消息),基于一天中的时间或用户,而无需更改主要应用程序。

答案 4 :(得分:0)

只需使用ajax执行process.let,当服务器承担负担时,用户继续活动。