在单击ASP.NET按钮后发送电子邮件,而不等待操作完成执行

在单击ASP.NET按钮后发送电子邮件,而不等待操作完成执行,asp.net,vb.net,asynchronous,webforms,fire-and-forget,Asp.net,Vb.net,Asynchronous,Webforms,Fire And Forget,简而言之,在HTTP上下文中,我希望用户在单击订单完成按钮后,不要等待邮件发送,然后再发送回“thak you页面” 我看到HostingEnvironment.QueueBackgroundWorkItem可以帮我解决这个问题,但它总是有被IIS回收杀死的风险 这样做的最佳解决方案是什么 我知道最好的办法是开发一个单独的控制台解决方案,但是对于3/4封电子邮件来说,这是不值得的,或者我可以考虑通过使它们异步来加速它。 Protected Sub btnConcludiOrdine_Click(

简而言之,在HTTP上下文中,我希望用户在单击订单完成按钮后,不要等待邮件发送,然后再发送回“thak you页面”

我看到HostingEnvironment.QueueBackgroundWorkItem可以帮我解决这个问题,但它总是有被IIS回收杀死的风险

这样做的最佳解决方案是什么

我知道最好的办法是开发一个单独的控制台解决方案,但是对于3/4封电子邮件来说,这是不值得的,或者我可以考虑通过使它们异步来加速它。

Protected Sub btnConcludiOrdine_Click(sender As Object, e As System.EventArgs) Handles btnConcludiOrdine.Click
    If IsValidOrder(Me._cart, msg) Then
      If Me._cart.SaveOrder(Me._user, Me._orderCode, Me._lang) then
           'Update quantity in db
           Dim mail As New EmailBLL
           mail.SendOrderNotice(Me._cart, Me._lang) '2 Mails
           mail.SendProductNotice() '2 Mails
      End If
    Else
      Response.Redirect("*Error URL*")
    End If
End Sub

只需在任务中推送您的发送邮件逻辑,若您对结果不感兴趣,就不要等待它。c#语法


按照建议的方法处理此问题–启动一个任务,或所谓的新处理器线程

因此,您要做的是分解代码——即使代码隐藏是针对web表单的,也可以这样做

因此,第一步是移出“慢”部分,或者我们想要分开运行的部分

主要问题是启动/启动/想要/渴望/实现一个全新的处理器线程

sub调用只能传递一个“参数”,sub只能接受一个参数

我注意到在你的例子中,例程需要两个值

但是,“一个参数”可以是“多个”值的数组,甚至可以是一个集合或任何东西。在我们的例子中,我们传递这两个值

所以请记住,您所调用的不能更新或“使用”窗体上控件的值–该窗体的实例将超出范围

但我们当然可以传递您需要的值。这将允许该例程100%独立于web表单运行

我也非常强烈的建议,如果你把子代码放在同一个网页后面?您应该/可以将该子组件标记为共享。如果该例程试图使用或更新表单上的控件值,那么这样做会让编译器对您生气并抛出错误

然而,更好的做法是将此子模块放在web表单代码后面的一个单独的标准代码模块中

不管上述情况如何,我们现在可以重新编写代码,如下所示:

If Me._cart.SaveOrder(Me._user, Me._orderCode, Me._lang) then
       
       Dim myInfo(1) as object
       myInfo(0) = me.cart
       myInfo(1) = me_._lng

       Call MyUpdateQ(myInfo) 
  End If
  ' bla bla lba


Shared Sub MyUPdateQ(p() as object)

       'Update quantity in db
       Dim mail As New EmailBLL

       mail.SendOrderNotice(p(0),p(1) 
       mail.SendProductNotice() '2 Mails

End Sub
好的,到目前为止,我们并没有取得太多的成就,但我们在这里写的是接受一个数组是关键

因此,现在请确保以上各项运行/工作正常,并且一切顺利

现在,因为我们将“工作负载”转移到了那个例程中,所以现在启动一个线程就很简单了

现在,我们上面的代码变成:

Protected Sub btnConcludiOrdine_Click(sender As Object, e As System.EventArgs) Handles btnConcludiOrdine.Click

   If IsValidOrder(Me._cart, msg) Then
      If Me._cart.SaveOrder(Me._user, Me._orderCode, Me._lang) then
         Dim myInfo(1) as object
         myInfo(0) = me.cart
         myInfo(1) = me_._lng

         Dim MyThread As New Thread(New ParameterizedThreadStart(AddressOf MyUpdateQ))

         MyThread.Start(myInfo)
      End If
   Else
      Response.Redirect("*Error URL*")
   End If
End Sub

Shared Sub MyUPdateQ(p() as object)

       'Update quantity in db
       Dim mail As New EmailBLL

       mail.SendOrderNotice(p(0),p(1) 
       mail.SendProductNotice() '2 Mails

End Sub

就是这样。现在,当您单击按钮时,它将等待零时间,因为长时间运行的例程现在将作为一个单独的线程100%运行。这也意味着,当用户点击按钮时,页面将立即响应,并向用户发回信息。因此,如果该线程需要6秒,甚至25秒,用户将不会注意到此延迟。

对不起,这些标记也不会因为IIS的回收而消失?我不这么认为。当我需要向另一台服务器发送一些关于操作的不太重要的信息时,我使用相同的做法。我认为这取决于您的IIS配置,如果在发送信息时强制回收,您肯定会丢失这些信息。我不想承担这种风险,电子邮件也可以延迟几分钟发送,但它们仍然很重要。如果标签(值)消失了,但没有什么能阻止您将它们放入某些变量中。邮件对象是一个独立的类-唯一的问题是您传递的两个值-只需将值提取到变量中-并将其传递给线程例程。我在下面概述了如何执行此操作。感谢您的回答,但在尝试实现(将在程序集类中实现)之前,我想了解的是:此线程的风险是什么?我读过很多文章,建议不要在web应用程序中使用被称为fire and forget的线程,因为IIS回收会导致后台进程。真的是这样吗?在生产环境(在线电子商务)中,我会造成损害吗?我认为没有太多风险。关键的概念是线程不应该(不能)尝试更新web表单。而且IIS的回收再也不是一个问题/问题了,不管怎么说,这比你的主代码线程更重要。现在,未处理的错误可能会触发重新循环,从而中断会话()。但是,如果您采用sql server来保存状态,那么重新循环问题就会大大消失。我有一个页面可以加载3-4个PDF。我将PDF显示为缩略图。虽然拇指指甲很小,但打开一个巨大的pdf+create拇指指甲可能需要3-5秒钟,所以我把它穿出来。效果很好
Protected Sub btnConcludiOrdine_Click(sender As Object, e As System.EventArgs) Handles btnConcludiOrdine.Click

   If IsValidOrder(Me._cart, msg) Then
      If Me._cart.SaveOrder(Me._user, Me._orderCode, Me._lang) then
         Dim myInfo(1) as object
         myInfo(0) = me.cart
         myInfo(1) = me_._lng

         Dim MyThread As New Thread(New ParameterizedThreadStart(AddressOf MyUpdateQ))

         MyThread.Start(myInfo)
      End If
   Else
      Response.Redirect("*Error URL*")
   End If
End Sub

Shared Sub MyUPdateQ(p() as object)

       'Update quantity in db
       Dim mail As New EmailBLL

       mail.SendOrderNotice(p(0),p(1) 
       mail.SendProductNotice() '2 Mails

End Sub