我正在尝试建立一个发送电子邮件的小型电子邮件工作者。电子邮件工作者在自己的线程中运行。 global.asax启动线程,然后在抛出此异常之前运行一轮。我一直试图找出它抛出的地方,但每次似乎都不同。记录打印到文本文件,以便工作,也许处置功能?
这是抛出的异常:
在电子邮件中开始新一轮 工人for-loop
去睡觉吧 电子邮件工作者for-loop
第一次机会 类型例外 '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;
}
答案 0 :(得分:3)
您需要将EmailWorker移出ASP.NET并进入Windows服务。您可以通过WCF在您的网页和服务之间进行通信。 ASP.NET不适用于长时间运行的任务。
答案 1 :(得分:1)
当您的应用程序关闭并且您致电ThreadAbortException
时,会发生EmailWorkerThread.Abort()
。这是预期的行为,它发生在随机位置,因为当Application_End
调用线程上的Abort()
时,代码可能位于不同的“点”。
根据MSDN,ThreadAbortException
是一个特殊的异常,即使在您的代码处理之后也始终重新抛出。它旨在让您知道线程正在关闭以便为您提供清理的机会。
您的应用程序可能正在关闭,因为IIS在一定量的空闲时间或其他强加的限制之后关闭了工作进程。同样,这是可以预料的,ASP.NET应用程序往往具有“有限的生命周期”,因此像这样长时间运行的线程并不是一个好主意。
我不确定你的确切问题是什么,但希望我能回答。
答案 2 :(得分: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 :(得分:0)
只要父线程处于活动状态,子线程就可以生存。即使你已经在应用程序级别定义了一个线程,我也无法想象这个线程实际上存在于HttpRequest线程之外。对我而言,这意味着您的请求线程终止的那一刻,您的孩子EmailWorkerThread终止。由于线程处于休眠状态,下一行会尝试执行,但它不能,因为HttpRequest线程已经运行了。
答案 4 :(得分:0)
ThreadAbortException
在线程工作并被中止时抛出。这发生在这个地方:
EmailWorkerThread.Abort();
当应用程序结束时,它无法捕获并发生。
更好的实现方法是用cancelable循环替换无限循环。