Recently I’ve found that ASP.NET HttpApplication may execute a single request in different threads. No this post is not about Async page feature of ASP.NET 2.0. It appeared that even ordinal page request execution can be done in different threads under big load.

I had the code which initialized TreadStatic field in the Application.BeginRequest handler. Then the pages and controls code used the created instance.

 

[ThreadStatic]
public static IScriptIncludable Includer = null;
protected void Application_BeginRequest(object sender, EventArgs e)
{
Utility.Includer = new PageScriptIncluder();
}
protected void Application_EndRequest(object sender, EventArgs e)
{
Utility.Includer = null;
}

 

I realized that sometimes I got the NullReferenceException when I clicked very fast at the site navigation menu. After adding a trace in the Application_BeginRequest and EndRequest to track the current thread it appeared that HttpApplication can switch the rendering of the page to the other tread than the one which executes BeginRequest. Here is the exception call stack:

System.Web.dll!System.Web.UI.Control.LoadRecursive() + 0x33 bytes
System.Web.dll!System.Web.UI.Page.ProcessRequestMain(bool includeStagesBeforeAsyncPoint = true, bool includeStagesAfterAsyncPoint = true) + 0x274 bytes
System.Web.dll!System.Web.UI.Page.ProcessRequest(bool includeStagesBeforeAsyncPoint, bool includeStagesAfterAsyncPoint = true) + 0x84 bytes
System.Web.dll!System.Web.UI.Page.ProcessRequest() + 0x51 bytes
System.Web.dll!System.Web.UI.Page.ProcessRequestWithNoAssert(System.Web.HttpContext context) + 0x16 bytes
System.Web.dll!System.Web.UI.Page.ProcessRequest(System.Web.HttpContext context) + 0x32 bytes
App_Web_xn8fhjxo.dll!ASP.about_default_aspx.ProcessRequest(System.Web.HttpContext context = {System.Web.HttpContext}) + 0x33 bytes	C#
System.Web.dll!System.Web.HttpApplication.CallHandlerExecutionStep.System.Web.HttpApplication.IExecutionStep.Execute() + 0xb6 bytes
System.Web.dll!System.Web.HttpApplication.ExecuteStep(System.Web.HttpApplication.IExecutionStep step = {System.Web.HttpApplication.CallHandlerExecutionStep}, ref bool completedSynchronously = true) + 0x4c bytes
System.Web.dll!System.Web.HttpApplication.ApplicationStepManager.ResumeSteps(System.Exception error) + 0x133 bytes
System.Web.dll!System.Web.HttpApplication.ResumeStepsFromThreadPoolThread(System.Exception error) + 0x25 bytes
System.Web.dll!System.Web.HttpApplication.AsyncEventExecutionStep.ResumeStepsWithAssert(System.Exception error) + 0x28 bytes
System.Web.dll!System.Web.HttpApplication.AsyncEventExecutionStep.OnAsyncEventCompletion(System.IAsyncResult ar) + 0x84 bytes
System.Web.dll!System.Web.HttpAsyncResult.Complete(bool synchronous, object result, System.Exception error, System.Web.RequestNotificationStatus status) + 0x3e bytes
System.Web.dll!System.Web.SessionState.SessionStateModule.PollLockedSessionCallback(object state) + 0x169 bytes
mscorlib.dll!System.Threading._TimerCallback.TimerCallback_Context(object state) + 0x2f bytes

Most interesting lines are at the bottom. After the _TimerCallback.TimerCallback_Context the HttpAllication resumes execution in another thread using AsyncEventExecutionStep and ApplicationStepManager.

I had a look into the HttpApplication code using Reflector and found out that at the beginning of the request handling Application creates a chain of steps, like Begin Request, Render Request and so on. Those steps are held in ApplicationStepManager and there is no guarantee that they will be called in the same thread.

My problem was fixed by simply using lazy loading ThreadStatic singleton instead of explicit object creation in the BeginRequest handle. Initialization of ThreadStatic fields in BeginRequest doesn’t make any sense.

Submit this story to DotNetKicks

Posted in: ASP.NET  Tags:

Currently rated 1.5 by 22 people

  • Currently 1.5/5 Stars.
  • 1
  • 2
  • 3
  • 4
  • 5