ASP.NET C# 线程中止异常?
我正在尝试构建一个小型电子邮件工作者来发送我的电子邮件。电子邮件工作人员在其自己的线程中运行。 global.asax 启动线程,然后在抛出此异常之前运行一轮。我一直试图找出它把它扔到哪里,但似乎每次都不一样。记录被打印到文本文件中以便可以工作,也许是处置功能?
这是抛出的异常:
在电子邮件中开始新一轮 工人for循环
要去睡觉了 电子邮件工作者 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;
}
i am trying to build a small email worker that sends my emails. The email worker operates in its own thread. The global.asax starts the thread and then it runs for one round before throwing this exception. I have been trying to find out where it throws it, but it seems to be different each time. The records are printed to the text file so that works, maybe the dispose functions?
This is the exception thrown:
Starting a new round in the email
worker for-loop
Going to sleep in the
email worker for-loop
A first chance
exception of type
'System.Threading.ThreadAbortException'
occurred in mscorlib.dll
An exception
of type
'System.Threading.ThreadAbortException'
occurred in mscorlib.dll but was not
handled in user code
This is the code for the 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;
}
}
}
}
This is the global.asax file that starts everything:
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;
}
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
发布评论
评论(5)
您正在创建的线程正被 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 封电子邮件,因此计时器滴答结束,新的一封邮件升起...
这在我们的生产环境中起作用...
当您的应用程序关闭并且您调用 EmailWorkerThread.Abort()
时,会发生 ThreadAbortException
。这是预期的行为,它会在随机位置发生,因为当 Application_End
在线程上调用 Abort()
时,代码可能位于不同的“点”。
根据 MSDN,ThreadAbortException 是一个特殊的异常,即使在代码处理之后也总是会重新抛出。它的目的是让您知道线程正在关闭,以便您有机会进行清理。
您的应用程序可能会关闭,因为 IIS 在经过设定的空闲时间或其他一些强加的限制后关闭工作进程。同样,这是可以预料的,ASP.NET 应用程序往往具有“有限的生命周期”,因此像这样长时间运行的线程并不是一个好主意。
我不确定你的具体问题是什么,但希望我能回答。
ThreadAbortException
顾名思义,当线程正在工作并被中止时抛出。这种情况发生在这个地方:
EmailWorkerThread.Abort();
它无法被捕获,并且在应用程序结束时发生。
更好的实现是将无限循环替换为 cancelable 循环。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
您需要将 EmailWorker 从 ASP.NET 移出并移至 Windows 服务中。您可以通过 WCF 在网页和服务之间进行通信。 ASP.NET 不适合长时间运行的任务。
You need to move the EmailWorker out of ASP.NET and into windows service. You can communicate between your webpage and the service via WCF. ASP.NET is not meant for long running tasks.