2010-12-17 70 views
2

我正在尝试构建一个发送我的电子邮件的小型电子邮件工作者。电子邮件工作人员在自己的线程中运行。 global.asax启动线程,然后运行一轮,然后抛出此异常。我一直在试图找出它扔到哪里,但每次看起来都不一样。记录打印到文本文件,以便工作,也许处置功能?ASP.NET C#线程中止异常?

这是抛出的异常:

开始在电子邮件的新一轮 工人for循环
要在 电子邮件工人睡环
第一个机会 异常类型的 'System.Threading.ThreadAbortException' 出现在mscorlib.dll
例外 型 'System.Threading.ThreadAbortException'的 mscorlib.dll中发生,但没有 用户代码

处理,这是EmailWorker

public static class EmailWorker 
{ 
    public static void Work() 
    { 
     TimeSpan sleepTime = new TimeSpan(0, 1, 0); 

     for (; ;) 
     { 
      Debug.WriteLine("Starting a new round in the email worker for-loop"); 
      try 
      { 
       // Get the records 
       CS_Code.UtopiaDataContext db = new CS_Code.UtopiaDataContext(); 
       List<CS_Code.Global_Email> emailsToSend = (from xx in db.Global_Emails select xx).ToList(); 


       // Write the records to a file (for now) 
       TextWriter writer = new StreamWriter(@"test.txt", true); // For debugging 
       foreach (var email in emailsToSend) 
        writer.WriteLine("To: " + email.Email_Address + ", Subject: " + email.Subject + ", uid:" + email.UserName.ToString()); 
       writer.Close(); 
       writer.Dispose(); 

       // Delete the used records from the database 
       foreach (var email in emailsToSend) 
        db.Global_Emails.DeleteOnSubmit(email); 
       db.SubmitChanges(); 
       db.Dispose(); 


       Debug.WriteLine("Going to sleep in the email worker for-loop"); 
       Thread.Sleep(sleepTime); // Sleep for 1 minute. 
       Debug.WriteLine("Just woke up in the email worker for-loop"); 
      } 
      catch (Exception e) 
      {    
       Debug.WriteLine(e.Message); 
       break; 
      } 
     } 
    } 
} 

此代码是启动一切Global.asax文件:

private static Thread EmailWorkerThread { get; set; } 

void Application_Start(object sender, EventArgs e) 
{ 
    // Email worker thread 
    if ((EmailWorkerThread == null) || (!EmailWorkerThread.IsAlive)) 
    { 
     ThreadStart ts = new ThreadStart(EmailWorker.Work); 
     EmailWorkerThread = new Thread(ts); 
     EmailWorkerThread.Start(); 
    } 
} 

void Application_End(object sender, EventArgs e) 
{ 
    // Email worker thread 
    if ((EmailWorkerThread != null) || (EmailWorkerThread.IsAlive)) 
     EmailWorkerThread.Abort(); 
    EmailWorkerThread = null; 
} 

回答

1

您正在创建的线程正在被asp.net中止。创建长时间运行的线程是asp.net中的一个主要禁忌。

我们有一个工作解决方法,我们并不感到自豪......创建一个计时器来处理待处理的电子邮件。

static Timer processTimer; // declare static at service level 

// At the static constructor: 
processTimer = new Timer(new TimerCallback(TimerTick), 60000, 10000, defaultInterval); //wait a minute before begin (dueTime = 60000) 

要格外小心,在Timer_Tick事件,处理最多N次邮件,所以计时器滴答结束,一个新的上升...

这是工作在我们的生产环境..

+3

这就是为什么您需要将24/7全天候运行到ASP.NET项目以及Windows Service中的东西。 – 2011-03-15 22:04:04

0

只要父线程处于活动状态,子线程就只能运行。即使你已经定义了一个看起来是应用程序级别的线程,但我无法想象这个线程实际上在HttpRequest线程之外生存。对我来说,这意味着当你的请求线程终止时,你的子EmailWorkerThread终止。由于线程正在休眠,下一行尝试执行,但不能执行,因为HttpRequest线程已经运行了它的进程。

+1

事实并非如此,您可以像应用程序一样在应用程序中启动线程,并且它们不会绑定到任何特定的请求线程。他的例外发生是因为_his code_告诉线程'Abort()'。 – CodingGorilla 2010-12-17 15:00:48

+0

@编码大猩猩 - 在哪里?我看到的唯一的终止是在应用程序结束。如果它没有绑定到请求线程,那么为什么终止调试写入在放弃之前不会被触发?我曾经在Asp.Net中使用过其他线程,但我从来没有试图在应用程序级代码中使用线程声明。 – 2010-12-17 15:02:52

+0

我相信最后的'Debug.Write(e.Message)'确实会触发。如果你看看他的异常,有:'在mscorlib.dll中发生类型'System.Threading.ThreadAbortException'的异常,但没有在用户代码中处理。这将是最后的信息,如果你阅读了关于ThreadAbortException的MSDN文档,你永远无法完全捕获它,它总是被重新抛出。 – CodingGorilla 2010-12-17 15:07:56

0

ThreadAbortException顾名思义,当线程正在工作并被中止时抛出。这发生在这个地方:

EmailWorkerThread.Abort(); 

它不能被捕获,它发生在你的应用程序结束时。

更好的实现方法是用cancelable循环代替无限循环。

1

当您的应用程序关闭并且您致电EmailWorkerThread.Abort()时,会出现ThreadAbortException。这是预期的行为,它发生在随机的地方,因为当Application_End在线程上调用Abort()时代码可能位于不同的“地点”。

根据MSDNThreadAbortException是一个特殊的例外,即使经过您的代码处理后,它总是被重新抛出。它的目的是让你知道线程正在关闭,给你一个清理的机会。

您的应用程序很可能正在关闭,因为IIS在设定的空闲时间量或其他强加的限制之后正在关闭工作进程。再次,这是可以预料的,ASP.NET应用程序往往有“有限的生命期”,所以像这样长时间运行的线程并不是一个好主意。

我不确定你确切的问题是什么,但希望我回答。

3

您需要将EmailWorker移出ASP.NET并转移到Windows服务中。您可以通过WCF在您的网页和服务之间进行通信。 ASP.NET不适用于长时间运行的任务。