网站上耗时的任务

本文关键字:任务 网站 | 更新日期: 2023-09-27 18:14:24

我的asp.net mvc 5项目,有一个页面,用户提交一个帖子,并收到一封关于他们刚刚发表的帖子的电子邮件。我如何构建我的程序,让用户看到一个网页,确认帖子已经立即发布,然后服务器发送一个单独的电子邮件?

这是我想到的:使用2个控制器动作。当确认页面加载时,它通过javascript调用发送电子邮件操作?有没有更好的解决方案?

电子邮件服务也可能会失败,但这不应该影响确认页面

UPDATE:当电子邮件发送或失败时,确认页面也应该通知用户

更新2:它应该执行1,然后立即返回。2的状态并不重要async的语法是什么?

public async Task<ActionResult> Confirm(string text)
{
    //1. Save post to database
    //2. Send email async
    return View();
}
如果我不关心交货失败,这就是我所需要的吗?

网站上耗时的任务

您可以使用SmtpClient.SendAsync()直接从控制器异步发送消息,假设您依赖System.Net.Mail作为提供者而不是外部扩展。

控制器语法示例:

    [HttpPost]
    public ActionResult PostData(object data)
    {
        //1. Save your post data here...
        MailMessage myMessage = new MailMessage();
        //2. Play with your message object here...
        SmtpClient myClient = new SmtpClient("your.smtp.com", 587);
        myClient.SendAsync(myMessage, "myToken");
        return View();
    }

你必须用Javascript处理视图中的返回值,如果你以后关心这些的话。

我不得不同意@ highc的观点——一封确认邮件,甚至是一个包含少量数据的HTML消息,都不应该花太长时间发送,以至于你需要担心异步操作。您可以通过执行以下操作来包含确认发送的邮件的原始请求:

    [HttpPost]
    public ActionResult PostData(object data)
    {
        //...Save your post data here...
        MailMessage myMessage = new MailMessage();
        //...Play with your message object here...
        SmtpClient myClient = new SmtpClient("your.smtp.com", 587);
        bool sentOk = true;
        try
        {
            myClient.Send(myMessage);
        }
        catch
        {
            sentOk = false;
        }
        return RedirectToAction("PostConfirmed", new { confirmEmail = sentOk });
    }

你可以做任何你想要生成的"PostConfirmed"视图,你可以使用confirmEmail布尔值来调整视图的内容取决于一个电子邮件错误。

这里也有一些关于async请求的更深入的信息。

EDIT:根据您对@HighCs关于连接失败的评论,考虑在您的SmtpClient配置中实现此功能:SmtpClient.Timeout()

你的标题是误导,因为发送电子邮件并不是一个真正耗时的任务,除非你希望发送大附件或做其他处理,以创建电子邮件的内容。根据我在大多数服务器上的经验,一封电子邮件以毫秒为单位发送。

对于您的示例,不需要添加两个控制器动作,也不需要异步。

你可以通过创建一个常规的动作来完成你想要的:

    [HttpPost]
    public ActionResult PostMessage(string messageText)
    {
        string result;
        try
        {
            // mail.Send() here
            // can use SendAsync but then need to handle result feedback via JavaScript
            result = "Email was sent";
        }
        catch
        {
            result = "Sending Email Failed";
        }
        return View("PostConfirmation", result);
    }

编辑:如果你有不可靠的网络,我会异步发送电子邮件,并在你的确认屏幕上显示"邮件排队"。

如果你想远离JavaScript轮询,那么只需在你的动作开始时存储来自后台任务的消息,例如:ViewBag。AsynchMessage = "你的帖子是通过电子邮件发送的"。只要将ViewBag包含在主布局中合适的位置,用户就可以在处理消息时看到它们。不要忘记在随后的请求中清空ViewBag,以保持UI的整洁。

如果您不想等待数据库保存和邮件发送,您可以创建一个任务并立即返回:

public ActionResult PostData(string text)
{
    //1. Save post to database
    var databaseTask = Task.Factory.StartNew(this.SavePostToDatabase);
    //2. Send email async
    databaseTask.ContinueWith(task => this.SendEmail());
    //3. Confirmation view
    return RedirectToAction("PostConfirmed");
}
protected void SendEmail()
{
    throw new NotImplementedException();
}
private void SavePostToDatabase()
{
    throw new NotImplementedException();
}