1

Anybody know why ASP.NET might not abort the current thread with a Response.End()?

Update: Reason being that there is code, albeit not well written, that is getting executed after Response.End(). I've never seen a case where Response.End () didn't stop the current thread from executing.


protected void Page_Load(object sender, EventArgs e)
{
        Response.Clear();
        Response.Redirect("somewhere", true);
        Response.End();

        //Some other code get's executed here
}
Trent
  • 2,122
  • 1
  • 24
  • 38
  • Why *would* it abort the thread? Surely that thread is just going to go back in the thread pool. (Caveat: I have not worked on the threading model of ASP since 1999; things may have changed since I last looked at that code.) – Eric Lippert Jan 14 '10 at 23:04
  • Response.End() DOES abort the thread. http://support.microsoft.com/kb/312629 – Cheeso Jan 14 '10 at 23:12
  • @Cheeso, it SHOULD, but it my case something is preventing. Rick Strahl has a little code snippet that shows a potential case that wouldn't abort the current thread. http://www.west-wind.com/WebLog/posts/368975.aspx – Trent Jan 14 '10 at 23:13
  • @Trent, but even he doesn't know *why* it works, which smacks of a subtle bug - looking at how it's supposed to work, the exception should continue being raised after his catch, and still not log his banner call. – Zhaph - Ben Duguid Jan 14 '10 at 23:25
  • 1
    @Zhaph, I'm really pointing to the code he outlined of what MS is doing *in* response.end():: public void End() { if (this._context.IsInCancellablePeriod) { InternalSecurityPermissions.ControlThread.Assert(); Thread.CurrentThread.Abort(new HttpApplication.CancelModuleException(false)); } else if (!this._flushing) { this.Flush(); this._ended = true; if (this._context.ApplicationInstance != null) { this._context.ApplicationInstance.CompleteRequest(); } } } – Trent Jan 14 '10 at 23:44
  • Yeah, I saw that bit - I can only assume something's caused your context to think it's not in a cancellable state - but I don't know what - unless Page_Load's not a cancellable step as per the IExecutionStep passed into ExecuteStep - I'd need to dig a little deeper to confirm that though. – Zhaph - Ben Duguid Jan 15 '10 at 00:24
  • Updated my response with more info, and possible things to look for as to why this might not be throwing the exception. – Zhaph - Ben Duguid Jan 15 '10 at 00:59
  • @EricLippert , could you confirm, that after Response.End the thread returns to the thread pool and the ASP.NET worker process is not likely to be recycled due to reduced number of threads. Please see my question  http://stackoverflow.com/questions/16878724/what-happens-with-asp-net-thread-after-response-end-threadabortexception – Michael Freidgeim Jun 03 '13 at 20:13
  • @MichaelFreidgeim: I can neither confirm nor deny that; I don't have the source code. All I have is the documentation, which says that Response.End does a thread abort. – Eric Lippert Jun 03 '13 at 20:22

4 Answers4

5

As you've pointed out, the method Response.End is defined as:

public void End()
{
  if (this._context.IsInCancellablePeriod) {
    InternalSecurityPermissions.ControlThread.Assert();
    Thread.CurrentThread.Abort(new HttpApplication.CancelModuleException(false));
  }
  else if (!this._flushing)
  {
    this.Flush();
    this._ended = true;
    if (this._context.ApplicationInstance != null) {
      this._context.ApplicationInstance.CompleteRequest();
    }
  }
}

Debugging a fairly simple web app with a break point in the Page_Load method, I can see the call stack includes the line:

System.Web.dll! System.Web.HttpApplication.ExecuteStep(System.Web.HttpApplication.IExecutionStep step = {System.Web.HttpApplication.CallHandlerExecutionStep}, ref bool completedSynchronously = true) + 0x4c bytes

Reflecting into CallHandlerExecutionStep I can see that the property IsCancellable is defined as:

bool HttpApplication.IExecutionStep.IsCancellable {
  get {
    return !(this._application.Context.Handler is IHttpAsyncHandler);
  }
}

The default handler for .aspx pages is the output from the PageHandlerFactory which implement IHttpHandler, not IHttpAsyncHandler - which would result in IsCancellable returning true (as indeed it does in my test app).

Have you configured a different HttpHandler in either your root web.config or one further up the stack to use an Async Handler instead? Are you using Update Panels with Partial Postbacks for example?

Zhaph - Ben Duguid
  • 26,785
  • 5
  • 80
  • 117
  • Nice work. Current codebase is a bit new to me, but I know there are some handlers in there. My first suspect was an ISAPI rewrite plugin, but there maybe something with these handlers. – Trent Jan 15 '10 at 16:29
2

You don't have it in a try block do you? That would throw a ThreadAbortException.

MikeW
  • 5,702
  • 1
  • 35
  • 43
1

According to Community comment on http://msdn.microsoft.com/en-us/library/a8wa7sdt(VS.80).aspx (select .NET framework 2.0) the current thread is not cancellable in Global.asax:

"Careful!! If you pass true, Response.Redirect() calls Response.End(), however there are certain circumstances where Response.End() does not raise the ThreadAbortException and instead sets a couple of flags and returns. One such situation is when you're in Global.asax, but it would occur more generically in any execution step that was not cancellable. I'll add details on Response.End(), but in a page you'd be fine, but in Global.asax processing will continue even if you pass true as the second parm."

I actually noticed this behaviour in one of my projects.

rboeije
  • 101
  • 4
0

I could be mistaken, but I believe for one thing the threads that are used are background threads that belong to a thread pool and are recycled so it doesn't kill the thread.

Response.End(), terminates the Response, but it doesn't return from the function.

protected void Page_Load(object sender, EventArgs e) 
{ 
        If(sometingBad)
        {
        Response.Clear(); 
        Response.Redirect("somewhere", true); 
        Response.End(); 
        return;
        }

        //Some other code get's executed here 
} 
Joel Barsotti
  • 3,031
  • 7
  • 35
  • 59