I have the following code in my codebehind (aspx.cs):
protected void button1_Click(object sender, EventArgs e)
{
new Thread(delegate() {
try
{
Thread.Sleep(30000); //do nothing for 30 seconds
}
catch (Exception ex)
{
//I AWLAYS get a ThreadAbortException here
//in about 1 second WHY!?!??!
}
}).Start();
}
Does ASP.NET kill all child threads when the request ends?
PS. I predict a lot of "because it's not best practice" answers. I know about best practices of running things in a windows service etc. I'm just curious WHY EXACTLY the thread is being killed in this particular code, given there's no "Response.Redirect", no "Response.End", no pool recycle, no IIS-restart etc etc (typical reasons people are repeating the "background thread in ASP.NET is bad" mantra).
UPDATE: As it turns out it works fine in ASP.NET MVC!!! The thread is aborted in Web-Forms only!! Which is even more weird. Any ideas?
Providing another solution: you don't need to set your page with the async
property. The following code will work fine:
new Thread
(
delegate()
{
try
{
MyMethod(myVar);
}
catch (Exception ex)
{
// handle
}
}
)
{
IsBackground = true
}.Start();
In this code, IsBackground = true
is what prevents the thread to be aborted when the request finishes.
Ok, so after 48 hours of experimenting here's what I found:
If you're on MVC - just start your threads as normal, they won't be aborted after the current request ends:
//MVC - works just fine
public ActionResult ThreadTest()
{
new Thread(delegate() {
try
{
System.Threading.Thread.Sleep(10000);
}
catch(Exception ex)
{
//no exception will be thrown
}
}).Start();
return Content("ok");
}
I learned that with webforms you can't use:
new Thread().Start(); //not working
ThreadPool.QueueUserWorkItem //not working
Action.BeginInvoke //not working
A bunch of other things - all not working
Here's what you need to do:
1) Mark your page as "async" in .aspx (this will tell ASP.NET to inherit the page from IAsyncHandler)
<%@ Page language="c#" Async="true" %>
2) Use BackgroundWorker in .aspx.cs
protected void button1_Click(object sender, EventArgs e)
{
var bg = new BackgroundWorker();
bg.DoWork += delegate
{
try
{
Thread.Sleep(10000); //do nothing for 10 seconds
}
catch (Exception ex)
{
//no excpeiton is thrown
}
};
bg.RunWorkerAsync();
}
HostingEnvironment.QueueBackgroundWorkItem
"The HostingEnvironment.QueueBackgroundWorkItem method lets you schedule small background work items. ASP.NET tracks these items and prevents IIS from abruptly terminating the worker process until all background work items have completed. This method can't be called outside an ASP.NET managed app domain."
Kudos to @danny-tuppeny for this last one
The end of a response usually does kill a thread, yes. If you call Response.End
you can even see that IIS throws a ThreadAbortedException
to immediately terminate the thread. In general, you shouldn't be performing any long running tasks in IIS, especially not on a Task or Background Thread. For more information about why you should avoid this, as well as how you can force IIS to handle your long running operations (if you really must) check out these links:
Stack Overflow Question on long running jobs in IIS
The dangers of background tasks in asp.net
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With