2011-02-23 96 views
3

有一个ASP.NET 2.0的Web应用程序应该允许发送电子邮件。我有一个立即发送电子邮件的Windows服务。我的Web应用程序根据某个模板编写电子邮件并将其放入MSMQ中,服务从此处获取。ASP.NET后台工作线程

问题是,编写来自模板的消息可能需要一些时间,并且我不希望用户在构建消息并将其传递给服务时等待。

我想了解一些后台进程,它将监听通知请求的内部队列。如果队列为空,则该进程什么都不做,但一旦出现消息,它就开始处理消息。我想只有一个进程不要创建大量线程。

目前我的想法是编写任务调度程序,它将包含通知请求的队列。当新项目被添加到队列中时,调度器检查发送通知的过程是否正在运行。如果是,那么它只是将请求添加到队列中。否则,它会创建一个新的线程,读取队列直到它为空并执行通知请求。

我的问题是我需要确保我的线程不会在ASP.NET完成对客户端的响应之后死掉,因为它是我的线程的父线程。问题是做这件事的最好方法是什么(或者可以做到这一点)?

P.S.如果IIS由于用户不活动而回收ASP.NET进程,我的线程就会死掉。

回答

1

我使用下面的类作为基类。我从这个类继承,并把我的逻辑放在里面。然后,我将这个类的实例存储在ASP.Net缓存中,以便保留一个引用,并且始终可以找到它。为了您的目的,在ExecuteProcess内部继承这个类之后,创建一个无限循环“while(true)”,然后在循环“thread.sleep(500)”的顶部/底部放置一个延迟,或类似的东西。每个循环检查队列中的消息。

Imports System.Threading 

Public MustInherit Class LongRunningProcess 
    Public ReadOnly Property Running() As Boolean 
     Get 
      Return _Running 
     End Get 
    End Property 

    Public ReadOnly Property Success() As Boolean 
     Get 
      Return _Success 
     End Get 
    End Property 

    Public ReadOnly Property Exception() As Exception 
     Get 
      Return _Exception 
     End Get 
    End Property 

    Public ReadOnly Property StartTime() As DateTime 
     Get 
      Return _StartTime 
     End Get 
    End Property 

    Public ReadOnly Property EndTime() As DateTime 
     Get 
      Return _EndTime 
     End Get 
    End Property 

    Public ReadOnly Property Args() As Object 
     Get 
      Return _Args 
     End Get 
    End Property 


    Protected _Running As Boolean = False 
    Protected _Success As Boolean = False 
    Protected _Exception As Exception = Nothing 
    Protected _StartTime As DateTime = DateTime.MinValue 
    Protected _EndTime As DateTime = DateTime.MinValue 
    Protected _Args() As Object = Nothing 
    Protected WithEvents _Thread As Thread 

    Private _locker As New Object() 

    Public Sub Execute(ByVal Arguments As Object) 
     SyncLock (_locker) 
      'if the process is not running, then...' 
      If Not _Running Then 
       'Set running to true' 
       _Running = True 
       'Set start time to now' 
       _StartTime = DateTime.Now 
       'set arguments' 
       _Args = Arguments 
       'Prepare to process in a new thread' 
       _Thread = New Thread(New ThreadStart(AddressOf ExecuteProcess)) 

       'Start the thread' 
       _Thread.Start() 
      End If 
     End SyncLock 
    End Sub 

    Protected MustOverride Sub ExecuteProcess() 
End Class 
+0

ASP.NET返回响应并终止处理响应的进程后,此线程是否会死机? – lostaman 2011-02-23 16:56:04

+0

@lostaman - 它将存活,线程属于对象,objet位于缓存中。所以它会一直活着,直到缓存死亡,这几乎是一个应用程序池/ iis重置。 – Peter 2011-02-23 17:40:54

+0

但是这个线程如何连接到缓存? – lostaman 2011-02-23 18:08:55

1

网站和当前发送电子邮件的Windows服务之间的中介服务如何?该站点可以将接收到的原始数据放入新服务的队列中,新服务将其拾取并编写消息,并将其放入发送电子邮件的Windows服务的队列中。这样,对网站和邮件服务的影响就很小,您只需向流中添加另一个队列即可。

您正在追求的想法是,所有不需要需要的数据处理都应该从现场网站卸载到后台服务(或任意数量的后台服务)中。该网站不是业务逻辑,它只是用户与幕后逻辑引擎进行交互的用户界面,其中服务是其中的一部分。所有网站或网站的任何部分需要做的是坚持数据并回到用户请求的响应。

+1

我同意最好的方法是将数据移动到单独的服务,但我不能在我的情况下做到这一点,因为模板机制必须与站点对象进行交互。因此我需要在ASP.NET中运行此过程。 – lostaman 2011-02-23 16:32:37

+1

@lostaman:听起来像是一些重构工作。各种应用程序上下文(站点,服务等)都应该访问核心业务功能,它们都不应该保留它。快速修复可能只是从服务项目中引用站点项目,以访问其内部类和成员,但这是一个马虎的方法。你一定想把业务逻辑从UI中拉出来。 – David 2011-02-24 10:56:05

+0

我完全同意你的看法。在我的情况下,我需要生成电子邮件消息并将其显示给用户。使用服务方法,我需要将数据传递给服务并从中获取准备好的消息。 – lostaman 2011-02-24 22:39:01

0

您可以创建一个Web服务,您可以在其中从ASP.NET应用程序进行异步调用。异步调用将允许您在不阻塞主线程的情况下进行调用。我认为你可以做一个方法调用,不必等待线程完成。