As our company delved into asynchronous transfers we noticed that we would get a random application hang every now and then. We suspected and tried to hunt down a threading problem and along the way we learned some interesting things.
First: Asp.Net queues requests by session to prevent this problem. Here is our test. First we built a new Page Class with some diagnostic info.
namespace WebApplication3
{
public class TestPage : Page
{
protected override void OnLoad(EventArgs e)
{
Debug.Print("strt\t" + this.GetType().Name + "Load" + " " +this.GetHashCode());
base.OnLoad(e);
Debug.Print(" stop\t" + this.GetType().Name + "Load"+ " " +this.GetHashCode());
}
protected override void OnPreRender(EventArgs e)
{
Debug.Print(" strt\t" + this.GetType().Name + "PreR"+ " " +this.GetHashCode());
base.OnPreRender(e);
Debug.Print(" stop\t" + this.GetType().Name + "PreR"+ " " +this.GetHashCode());
}
}
}
Then I setup the Default Page to add iframes to the source.
public partial class _Default : TestPage
{
protected void Page_Load(object sender, EventArgs e)
{
Thread.Sleep(1000);
for (int i = 0; i < 20; i++)
{
HtmlGenericControl control = new HtmlGenericControl("iframe");
control.Attributes.Add("src", "WebForm1.aspx");
this.Form.Controls.Add(control);
}
}
}
Some notes here. The Thread.Sleep makes sure that the debugger is attached and responding well enough to record things correctly.
Finally WebForm1.aspx. This thing doesnt do anything but inherit from the TestPage with diagnostic information.
namespace WebApplication3
{
public partial class WebForm1 : TestPage
{
protected void Page_Load(object sender, EventArgs e)
{
}
}
}
Ok so the first run we make sure EnableSessionState="True"
What this is supposed to do is make sure that only one request happens at a time. Here is the log.
strt default_aspxLoad 53576792
stop default_aspxLoad 53576792
strt default_aspxPreR 53576792
stop default_aspxPreR 53576792
strt webform1_aspxLoad 46058179
strt webform1_aspxLoad 63986957
stop webform1_aspxLoad 46058179
strt webform1_aspxPreR 46058179
stop webform1_aspxPreR 46058179
stop webform1_aspxLoad 63986957
strt webform1_aspxPreR 63986957
stop webform1_aspxPreR 63986957
strt webform1_aspxLoad 58678956
stop webform1_aspxLoad 58678956
strt webform1_aspxPreR 58678956
stop webform1_aspxPreR 58678956
strt webform1_aspxLoad 49300528
stop webform1_aspxLoad 49300528
strt webform1_aspxPreR 49300528
stop webform1_aspxPreR 49300528
strt webform1_aspxLoad 8423152
stop webform1_aspxLoad 8423152
strt webform1_aspxPreR 8423152
stop webform1_aspxPreR 8423152
strt webform1_aspxLoad 32996321
stop webform1_aspxLoad 32996321
strt webform1_aspxPreR 32996321
stop webform1_aspxPreR 32996321
strt webform1_aspxLoad 28848020
stop webform1_aspxLoad 28848020
strt webform1_aspxPreR 28848020
stop webform1_aspxPreR 28848020
strt webform1_aspxLoad 66504299
stop webform1_aspxLoad 66504299
strt webform1_aspxPreR 66504299
stop webform1_aspxPreR 66504299
strt webform1_aspxLoad 47123389
stop webform1_aspxLoad 47123389
strt webform1_aspxPreR 47123389
stop webform1_aspxPreR 47123389
strt webform1_aspxLoad 60889463
stop webform1_aspxLoad 60889463
strt webform1_aspxPreR 60889463
stop webform1_aspxPreR 60889463
strt webform1_aspxLoad 16515137
stop webform1_aspxLoad 16515137
strt webform1_aspxPreR 16515137
stop webform1_aspxPreR 16515137
strt webform1_aspxLoad 10378086
stop webform1_aspxLoad 10378086
strt webform1_aspxPreR 10378086
stop webform1_aspxPreR 10378086
strt webform1_aspxLoad 58791803
stop webform1_aspxLoad 58791803
strt webform1_aspxPreR 58791803
stop webform1_aspxPreR 58791803
strt webform1_aspxLoad 45784774
stop webform1_aspxLoad 45784774
strt webform1_aspxPreR 45784774
stop webform1_aspxPreR 45784774
strt webform1_aspxLoad 31806433
stop webform1_aspxLoad 31806433
strt webform1_aspxPreR 31806433
stop webform1_aspxPreR 31806433
strt webform1_aspxLoad 17398656
stop webform1_aspxLoad 17398656
strt webform1_aspxPreR 17398656
stop webform1_aspxPreR 17398656
strt webform1_aspxLoad 62912648
stop webform1_aspxLoad 62912648
strt webform1_aspxPreR 62912648
stop webform1_aspxPreR 62912648
strt webform1_aspxLoad 50833736
stop webform1_aspxLoad 50833736
strt webform1_aspxPreR 50833736
stop webform1_aspxPreR 50833736
strt webform1_aspxLoad 46154167
stop webform1_aspxLoad 46154167
strt webform1_aspxPreR 46154167
stop webform1_aspxPreR 46154167
strt webform1_aspxLoad 63078365
stop webform1_aspxLoad 63078365
strt webform1_aspxPreR 63078365
stop webform1_aspxPreR 63078365
So the first request does not seem to be blocking additional requests as seen in red. Whoops! We didn't use Session so asp.net hasn't made us a session (this is retarded I know).
So we made a change to TestPage.
public class TestPage : Page
{
protected override void OnLoad(EventArgs e)
{
Session["dumb"] = true;
Debug.Print("strt\t" + this.GetType().Name + "Load" + " " +this.GetHashCode());
base.OnLoad(e);
Debug.Print(" stop\t" + this.GetType().Name + "Load"+ " " +this.GetHashCode());
}
protected override void OnPreRender(EventArgs e)
{
Debug.Print(" strt\t" + this.GetType().Name + "PreR"+ " " +this.GetHashCode());
base.OnPreRender(e);
Debug.Print(" stop\t" + this.GetType().Name + "PreR"+ " " +this.GetHashCode());
}
}
}
See now we set ["Dumb"]=true.
Ok so here is the next trace with that fix.
strt default_aspxLoad 6100737
stop default_aspxLoad 6100737
strt default_aspxPreR 6100737
stop default_aspxPreR 6100737
strt webform1_aspxLoad 6299240
stop webform1_aspxLoad 6299240
strt webform1_aspxPreR 6299240
stop webform1_aspxPreR 6299240
strt webform1_aspxLoad 50224890
stop webform1_aspxLoad 50224890
strt webform1_aspxPreR 50224890
stop webform1_aspxPreR 50224890
strt webform1_aspxLoad 51844981
stop webform1_aspxLoad 51844981
strt webform1_aspxPreR 51844981
stop webform1_aspxPreR 51844981
strt webform1_aspxLoad 54842390
stop webform1_aspxLoad 54842390
strt webform1_aspxPreR 54842390
stop webform1_aspxPreR 54842390
strt webform1_aspxLoad 44186085
stop webform1_aspxLoad 44186085
strt webform1_aspxPreR 44186085
stop webform1_aspxPreR 44186085
strt webform1_aspxLoad 307537
stop webform1_aspxLoad 307537
strt webform1_aspxPreR 307537
stop webform1_aspxPreR 307537
strt webform1_aspxLoad 36642531
stop webform1_aspxLoad 36642531
strt webform1_aspxPreR 36642531
stop webform1_aspxPreR 36642531
strt webform1_aspxLoad 8761922
stop webform1_aspxLoad 8761922
strt webform1_aspxPreR 8761922
stop webform1_aspxPreR 8761922
strt webform1_aspxLoad 44283204
stop webform1_aspxLoad 44283204
strt webform1_aspxPreR 44283204
stop webform1_aspxPreR 44283204
strt webform1_aspxLoad 37119060
stop webform1_aspxLoad 37119060
strt webform1_aspxPreR 37119060
stop webform1_aspxPreR 37119060
strt webform1_aspxLoad 46442220
stop webform1_aspxLoad 46442220
strt webform1_aspxPreR 46442220
stop webform1_aspxPreR 46442220
strt webform1_aspxLoad 51538364
stop webform1_aspxLoad 51538364
strt webform1_aspxPreR 51538364
stop webform1_aspxPreR 51538364
strt webform1_aspxLoad 65304700
stop webform1_aspxLoad 65304700
strt webform1_aspxPreR 65304700
stop webform1_aspxPreR 65304700
strt webform1_aspxLoad 45154067
stop webform1_aspxLoad 45154067
strt webform1_aspxPreR 45154067
stop webform1_aspxPreR 45154067
strt webform1_aspxLoad 24313979
stop webform1_aspxLoad 24313979
strt webform1_aspxPreR 24313979
stop webform1_aspxPreR 24313979
strt webform1_aspxLoad 30823158
stop webform1_aspxLoad 30823158
strt webform1_aspxPreR 30823158
stop webform1_aspxPreR 30823158
strt webform1_aspxLoad 32261192
stop webform1_aspxLoad 32261192
strt webform1_aspxPreR 32261192
stop webform1_aspxPreR 32261192
strt webform1_aspxLoad 5695327
stop webform1_aspxLoad 5695327
strt webform1_aspxPreR 5695327
stop webform1_aspxPreR 5695327
strt webform1_aspxLoad 14547257
stop webform1_aspxLoad 14547257
strt webform1_aspxPreR 14547257
stop webform1_aspxPreR 14547257
strt webform1_aspxLoad 65008279
stop webform1_aspxLoad 65008279
strt webform1_aspxPreR 65008279
stop webform1_aspxPreR 65008279
So great! It finally works. Now lets break it on purpose. We setup this line in both pages.
EnableSessionState="ReadOnly"
Here is our log we can see that the first 2 requests to webform1 are made at the same time causing a thread exception.
strt default_aspxLoad 22177797
stop default_aspxLoad 22177797
strt default_aspxPreR 22177797
stop default_aspxPreR 22177797
strt webform1_aspxLoad 58758044
strt webform1_aspxLoad 60402358
stop webform1_aspxLoad 60402358
stop webform1_aspxLoad 58758044
strt webform1_aspxPreR 60402358
strt webform1_aspxPreR 58758044
stop webform1_aspxPreR 60402358
stop webform1_aspxPreR 58758044
strt webform1_aspxLoad 33970112
stop webform1_aspxLoad 33970112
strt webform1_aspxPreR 33970112
stop webform1_aspxPreR 33970112
strt webform1_aspxLoad 12544008
stop webform1_aspxLoad 12544008
strt webform1_aspxPreR 12544008
stop webform1_aspxPreR 12544008
strt webform1_aspxLoad 47231162
stop webform1_aspxLoad 47231162
strt webform1_aspxPreR 47231162
stop webform1_aspxPreR 47231162
strt webform1_aspxLoad 63638306
stop webform1_aspxLoad 63638306
strt webform1_aspxPreR 63638306
stop webform1_aspxPreR 63638306
strt webform1_aspxLoad 57701674
stop webform1_aspxLoad 57701674
strt webform1_aspxPreR 57701674
stop webform1_aspxPreR 57701674
strt webform1_aspxLoad 29746117
stop webform1_aspxLoad 29746117
strt webform1_aspxPreR 29746117
stop webform1_aspxPreR 29746117
strt webform1_aspxLoad 3884878
stop webform1_aspxLoad 3884878
strt webform1_aspxPreR 3884878
stop webform1_aspxPreR 3884878
strt webform1_aspxLoad 45476154
stop webform1_aspxLoad 45476154
strt webform1_aspxPreR 45476154
stop webform1_aspxPreR 45476154
strt webform1_aspxLoad 42317455
stop webform1_aspxLoad 42317455
strt webform1_aspxPreR 42317455
stop webform1_aspxPreR 42317455
strt webform1_aspxLoad 60918874
stop webform1_aspxLoad 60918874
strt webform1_aspxPreR 60918874
stop webform1_aspxPreR 60918874
strt webform1_aspxLoad 54806812
stop webform1_aspxLoad 54806812
strt webform1_aspxPreR 54806812
stop webform1_aspxPreR 54806812
strt webform1_aspxLoad 59055457
stop webform1_aspxLoad 59055457
strt webform1_aspxPreR 59055457
stop webform1_aspxPreR 59055457
strt webform1_aspxLoad 64646201
stop webform1_aspxLoad 64646201
strt webform1_aspxPreR 64646201
stop webform1_aspxPreR 64646201
strt webform1_aspxLoad 62849758
stop webform1_aspxLoad 62849758
strt webform1_aspxPreR 62849758
stop webform1_aspxPreR 62849758
strt webform1_aspxLoad 26235852
stop webform1_aspxLoad 26235852
strt webform1_aspxPreR 26235852
strt webform1_aspxLoad 2135755
stop webform1_aspxLoad 2135755
stop webform1_aspxPreR 26235852
strt webform1_aspxPreR 2135755
stop webform1_aspxPreR 2135755
strt webform1_aspxLoad 6565686
stop webform1_aspxLoad 6565686
strt webform1_aspxPreR 6565686
stop webform1_aspxPreR 6565686
strt webform1_aspxLoad 8372655
stop webform1_aspxLoad 8372655
strt webform1_aspxPreR 8372655
stop webform1_aspxPreR 8372655
So in summary asp.net only makes one request at a time as long as you initialize the session, set the EnableSessionState=True (which is the default). So if you think Asp.Net is causing threading issues think again.