Hedge - this could end up being a 'dumb newbie' question, but if not it could be one of the more interesting posts today.
Basically, I'm seeing that merely adding a Global.asax component to a web application causes the runtime to execute page requests serially, whereas web applications without a Global.asax process requests in parallel as expected. Impact would be that scalability goes out the window if you use Global.asax - I'm skeptical that's actually the case but am currently blocked on any better explanation.
Here's the scenario:
- Create a new blank web application.
Add a page that takes 5 seconds or so to complete. I used the below but the exact method of delay doesn't seem to matter:
DateTime PageStartTime = DateTime.Now;
while (DateTime.Now < PageStartTime.AddMilliseconds(5000)) { System.Threading.Thread.Sleep(0); }
Add another page to use as a utility to reset the app domain. This isn't strictly necessary to see the problem behavior but is helpful in repeating the tests:
HttpRuntime.UnloadAppDomain();
After building, start a browser with one tab (or window) for the app domain reset, and 3 tabs (or windows) for the long-running page.
F5 the 'reset' page, wait a sec, then F5 the 3 'delay page' tabs. You'll see that (as expected) the 3 pages end about the same time, i.e. that they're clearly running in parallel. Run all the F5's you want and they'll still parallel as expected, presumably until the cows come home.
Back to the project, add a 'Global Application Class' (Gloabl.asax) component. No need to add any code - mere presence of the component is the test basis.
After building, return to browser and quickly F5 the 4 tabs. Again, the long-running pages parallel as expected, at least if you hit the 3 tabs fairly quickly. Now for the good part - wait a sec until all complete, then (without using the reset tab) F5 the 3 'delay' pages again - you'll see that:
a. The total time for all 3 to run is about 15 seconds - 3 times longer than expected. The pages appear to be processed serially, i.e. one after the other.
b. The order of completion for the second and third tabs is random, suggesting that ASP hasn't even decided which should run first until after the first request has completed.
c. If you reset (unload) the app domain, you get another chance to have the pages parallel, but after they complete that first cycle they go right back to serial execution.
Back to the project, remove the Global.asax component, build, and retest - the page requests again parallel as expected for the long-haul.
Cool, eh?
Stuff I tried:
- Various .Net versions - 3.5 and 4,
- Various web servers - WebDev, UltiDev, IIS,
- Different ways of delaying the page - real work, with and without yield, etc,
- Browser usage - one browser window with multiple tabs, versus dedicated browser windows,
- Code placement - tried both page 'Load' and 'PreRender' events for delay code, ~. Other stuff now rolled off of gray-haired memory...
Clearly the above isn't a representative or useful project, but I stumbled on this doing something that has both intentionally long-running pages and an actual need for Global.asax - mainly for global static variables. I imagine most 'normal' web apps would run fast enough that few would notice if they reverted to sequential request execution, but this behavior sure broke mine - been hammering this for three days so any ideas most appreciated!
Thanks, David