PRB: Nested Virtual Roots Can Lose Session State

This article was previously published under Q173307
This article has been archived. It is offered "as is" and will no longer be updated.
Symptoms
When you browse to a child virtual root that is nested within a parentvirtual root and then navigate to the parent virtual root session,variables appear to be lost.

The following table summarizes the behavior:
                             Child 1 app state held  Child 2 app state held   Root app called first                    No                No   Root app called before Child 1 only      No                Yes   Root app called before Child 2 only      Yes               No   Root app called last                     Yes               Yes				
Cause
NOTE: There is a registry entry, CheckForNestedVroots(Default = 1), that ASP uses to check for nested virtual roots so that if a new nested virtual root is created while the system is running, the running application sees the new nested Global.asa file as soon as it is saved. From this registry parameter you can infer that ASP is designed to check for Global.asa files in subdirectories.

However, this behavior works in only one case: If all nested applications start before the root application, ASP checks for Global.asa files in all linked applications (both above and at the same level of the calling application). However, if the root application is called first or called before any nested application, only the root application's session state (sessionid and session variables) is maintained; it is not as if ASP does not check for nested virtual roots.
Internet Service Manager allows users to set up directories and theirsubdirectories as virtual roots. This creates a situation where there arevirtual roots with nested virtual roots, which themselves can containGlobal.asa files with Application_OnStart and Session_OnStart subroutines.

Here is an example directory structure in which each virtual directorycontains a Global.asa file:
   C:\InetPub\wwwroot <Home>   Global.asa      C:\InetPub\wwwroot\Test2 (Nested)      Global.asa           C:\InetPub\wwwroot\Test2\Test3 (Nested)           Global.asa   C:\InetPub\wwwroot\Test4   Global.asa					
After the user browses to the root directory, which is the Wwwroot directory in a default installation, the SessionID is created and doesnot change even when navigating to other nested virtual roots, but theApplication-scoped variables continue to change each time the users browsesa page in a different virtual root. This causes the Application variablesto appear to be lost.

However, if the root directory is the last directory navigated to and hasnever been visited before, then each nested directory maintains its ownSessionID and Application and Session scoped variables.

This behavior is caused by the fact that once the root <home> directory is browsed, IIS continues to send the same SessionCookie back to the browser; however, if nested virtual roots are browsed prior to browsing the home root, SessionCookies are sent for each nested virtual root, thereby generating multiple SessionIDs for each nested virtual root. The first time the home root is browsed the SessionCookie is fixed thereafter.
Resolution
Do not use nested virtual roots when you design Web projects; instead, useone virtual root for each Web project that contains the Global.asa for thatproject.
Status
This behavior is by design.
More information

Steps to Reproduce Behavior

  1. Configuration: In Microsoft Internet Service Manager, "Enable Default Document" in the Directories tab needs to include "Default.asp."
  2. Using Windows Explorer create a directory named WWWTest2 under the InetPub\wwwroot directory. Create a subdirectory under WWWTest2 called WWWTest3. Then create a directory at the same level as WWWTest2 called WWWTest4.
  3. Copy the following Global.asa file into the WWWRoot directory:
       <SCRIPT LANGUAGE=VBScript RUNAT=Server>   Sub Application_OnStart     Application("MyTestApplication") = "WWWRoot: Welcome to _       Application Level Scope!"     Application("WWWRoot") = "Chickens Eat..."   Response.Write("Fire Application_OnStart for WWWRoot" & "<br>")   End Sub   Sub Session_OnStart     Session("MyTestSession") = "WWWRoot: Welcome to session       level scope!"     Session("SessionID") = Session.SessionID     Session("WWWRoot") = "Chicken Food!"     Response.Write("Fire Session_OnStart for WWWRoot" & "<br>")   End Sub   </SCRIPT>					
  4. Copy the following Default.asp file into the WWWRoot directory:
       <%@ LANGUAGE="VBSCRIPT" %>   <HTML>   <HEAD>   <META NAME="GENERATOR" Content="Microsoft Visual InterDev 1.0">   <META HTTP-EQUIV="Content-Type" content="text/html;   charset=iso-8859-1">   <TITLE>Test Nested Virtual Roots</TITLE>   </HEAD>   <BODY>   <%   Response.Write("Common Variable Names:" & "<br>")   Response.Write Application("MyTestApplication") & "<br>"   Response.Write Session("MyTestSession") & "<br>"   Response.Write "Session.SessionID = " &     Session("SessionID") & "<br><p>"   Response.Write("Application Scoped Variables:" & "<br>")   Response.Write "WWWRoot: " & Application("WWWRoot") & "<br>"   Response.Write "WWWTest2: " & Application("WWWTest2") & "<br>"   Response.Write "WWWTest3: " & Application("WWWTest3") & "<br>"   Response.Write "WWWTest4: " & Application("WWWTest4") & "<br><p>"   Response.Write("Session Scoped Variables:" & "<br>")   Response.Write "WWWRoot: " & Session("WWWRoot") & "<br>"   Response.Write "WWWTest2: " & Session("WWWTest2") & "<br>"   Response.Write "WWWTest3: " & Session("WWWTest3") & "<br>"   Response.Write "WWWTest4: " & Session("WWWTest4") & "<br><p>"   %>   <BR>   <P>   <A   HREF=<WWLINK TYPE="GENERIC"      VALUE="http://<%=Request.ServerVariables("SERVER_NAME")%>/WWWTest2/>_">http://<%=Request.ServerVariables("SERVER_NAME")%>/WWWTest2/>_</WWLINK>   Click here to go to WWWTest2</A><BR>   <A   HREF=<WWLINK TYPE="GENERIC" VALUE="http://<%=Request.ServerVariables("SERVER_NAME")%>/WWWTest3/>_">http://<%=Request.ServerVariables("SERVER_NAME")%>/WWWTest3/>_</WWLINK>   Click here to go to WWWTest3>/A><BR>   <A   HREF=<WWLINK TYPE="GENERIC" VALUE="http://<%=Request.ServerVariables("SERVER_NAME")%>/WWWTest4/>_">http://<%=Request.ServerVariables("SERVER_NAME")%>/WWWTest4/>_</WWLINK>   Click here to go to WWWTest4>/A><BR>   </BODY>   </HTML>					
  5. Copy the following Global.asa file into the WWWTest2 directory:
       <SCRIPT LANGUAGE=VBScript RUNAT=Server>   Sub Application_OnStart     Application("MyTestApplication") = "WWWTest2: Welcome to _     Application Level Scope!"     Application("WWWTest2") = "Dogs Eat..."   Response.Write("Fire Application_OnStart for WWWTest2" & "<br>")   End Sub   Sub Session_OnStart     Session("MyTestSession") = "WWWTest2: Welcome to session_        level scope!"     Session("SessionID") = Session.SessionID     Session("WWWTest2") = "Dog Food!"    Response.Write("Fire Session_OnStart for WWWTest2" & "<br>")   End Sub   </SCRIPT>					
  6. Copy the following Default.asp file into the WWWTest2 directory:
       <%@ LANGUAGE="VBSCRIPT" %>   <HTML>   <HEAD>   <META NAME="GENERATOR" Content="Microsoft Visual InterDev 1.0">   <META HTTP-EQUIV="Content-Type" content="text/html;      charset=iso-8859-1">   <TITLE>Test Nested Virtual Roots</TITLE>   </HEAD>   <BODY>   <%   Response.Write("Common Variable Names:" & "<br>")   Response.Write Application("MyTestApplication") & "<br>"   Response.Write Session("MyTestSession") & "<br>"   Response.Write "Session.SessionID = " & Session("SessionID")     & "<br><p>"   Response.Write("Application Scoped Variables:" & "<br>")   Response.Write "WWWRoot: " & Application("WWWRoot") & "<br>"   Response.Write "WWWTest2: " & Application("WWWTest2") & "<br>"   Response.Write "WWWTest3: " & Application("WWWTest3") & "<br>"   Response.Write "WWWTest4: " & Application("WWWTest4") & "<br><p>"   Response.Write("Session Scoped Variables:" & "<br>")   Response.Write "WWWRoot: " & Session("WWWRoot") & "<br>"   Response.Write "WWWTest2: " & Session("WWWTest2") & "<br>"   Response.Write "WWWTest3: " & Session("WWWTest3") & "<br>"   Response.Write "WWWTest4: " & Session("WWWTest4") & "<br><p>"   %>   <BR>   <P>   <A   HREF=http://<%=Request.ServerVariables("SERVER_NAME")%>/WWWRoot/>_   Click here to go to WWWRoot</A><BR>   <A   HREF=http://<%=Request.ServerVariables("SERVER_NAME")%>/WWWTest3/>_   Click here to go to WWWTest3</A><BR>   <A   HREF=http://<%=Request.ServerVariables("SERVER_NAME")%>/WWWTest4/>_   Click here to go to WWWTest4</A><BR>   </BODY>   </HTML>					
  7. Copy the following Global.asa file into the WWWTest3 directory:
       <SCRIPT LANGUAGE=VBScript RUNAT=Server>   Sub Application_OnStart     Application("MyTestApplication") = "WWWTest3: Welcome to _       Application Level Scope!"     Application("WWWTest3") = "Cows Eat..."   Response.Write("Fire Application_OnStart for WWWTest3" & "<br>")   End Sub   Sub Session_OnStart     Session("MyTestSession") = "WWWTest3: Welcome to session_       level scope!"     Session("SessionID") = Session.SessionID     Session("WWWTest3") = "Cow Food!"     Response.Write("Fire Session_OnStart for WWWTest3" & "<br>")   End Sub   </SCRIPT>					
  8. Copy the following Default.asp file into the WWWTest3 directory:
       <%@ LANGUAGE="VBSCRIPT" %>   <HTML>   <HEAD>   <META NAME="GENERATOR" Content="Microsoft Visual InterDev 1.0">   <META HTTP-EQUIV="Content-Type" content="text/html; _      charset=iso-8859-1">   <TITLE>Test Nested Virtual Roots</TITLE>   </HEAD>   <BODY>   <%   Response.Write("Common Variable Names:" & "<br>")   Response.Write Application("MyTestApplication") & "<br>"   Response.Write Session("MyTestSession") & "<br>"   Response.Write "Session.SessionID = " & Session("SessionID") & "   <br><p>"   Response.Write("Application Scoped Variables:" & "<br>")   Response.Write "WWWRoot: " & Application("WWWRoot") & "<br>"   Response.Write "WWWTest2: " & Application("WWWTest2") & "<br>"   Response.Write "WWWTest3: " & Application("WWWTest3") & "<br>"   Response.Write "WWWTest4: " & Application("WWWTest4") & "<br><p>"   Response.Write("Session Scoped Variables:" & "<br>")   Response.Write "WWWRoot: " & Session("WWWRoot") & "<br>"   Response.Write "WWWTest2: " & Session("WWWTest2") & "<br>"   Response.Write "WWWTest3: " & Session("WWWTest3") & "<br>"   Response.Write "WWWTest4: " & Session("WWWTest4") & "<br><p>"   %>   <BR>   <P>   <A   HREF=http://<%=Request.ServerVariables("SERVER_NAME")%>/WWWRoot/>_   Click here to go to WWWRoot</A><BR>  <A HREF=http://<%=Request.ServerVariables("SERVER_NAME")%>/WWWTest2/>   Click_ here to go to WWWTest2</A><BR>   <A   HREF=http://<%=Request.ServerVariables("SERVER_NAME")%>/WWWTest4/>   Click here to go to WWWTest4</A><BR>   </BODY>   </HTML>					
  9. Copy the following Global.asa file into the WWWTest4 directory:
       <SCRIPT LANGUAGE=VBScript RUNAT=Server>   Sub Application_OnStart     Application("MyTestApplication") = "WWWTest4: Welcome to _       Application Level Scope!"     Application("WWWTest4") = "Tony Drinks..."   Response.Write("Fire Application_OnStart for WWWTest4" & "<br>")   End Sub   Sub Session_OnStart     Session("MyTestSession") = "WWWTest4: Welcome to session_        level scope!"     Session("SessionID") = Session.SessionID     Session("WWWTest4") = "Good Wine!"     Response.Write("Fire Session_OnStart for WWWTest4" & "<br>")   End Sub   </SCRIPT>					
  10. Copy the following Default.asp file into the WWWTest4 directory:
    <%@ LANGUAGE="VBSCRIPT" %>     <HTML>     <HEAD>     <META NAME="GENERATOR" Content="Microsoft Visual InterDev 1.0">     <META HTTP-EQUIV="Content-Type" content="text/html;_        charset=iso-8859-1">     <TITLE>Test Nested Virtual Roots</TITLE>     </HEAD>     <BODY>     <%     Response.Write("Common Variable Names:" & "<br>")     Response.Write Application("MyTestApplication") & "<br>"     Response.Write Session("MyTestSession") & "<br>"     Response.Write "Session.SessionID = " & Session("SessionID") &        "<br><p>"     Response.Write("Application Scoped Variables:" & "<br>")     Response.Write "WWWRoot: " & Application("WWWRoot") & "<br>"     Response.Write "WWWTest2: " & Application("WWWTest2") & "<br>"     Response.Write "WWWTest3: " & Application("WWWTest3") & "<br>"     Response.Write "WWWTest4: " & Application("WWWTest4") & "<br><p>"     Response.Write("Session Scoped Variables:" & "<br>")     Response.Write "WWWRoot: " & Session("WWWRoot") & "<br>"     Response.Write "WWWTest2: " & Session("WWWTest2") & "<br>"     Response.Write "WWWTest3: " & Session("WWWTest3") & "<br>"     Response.Write "WWWTest4: " & Session("WWWTest4") & "<br><p>"     %>     <BR>     <P>     <A     HREF=http://<%=Request.ServerVariables("SERVER_NAME")%>/WWWRoot/>     Click here to go to WWWRoot</A><BR>     <A     HREF=http://<%=Request.ServerVariables("SERVER_NAME")%>/WWWTest2/>     Click here to go to WWWTest2</A><BR>     <A     HREF=http://<%=Request.ServerVariables("SERVER_NAME")%>/WWWTest3/>     Click here to go to WWWTest3</A><BR>     </BODY>     </HTML>					
  11. Open Internet Service Manager, right-click the WWWService and select the Directories tab. Click Add and add WWWTest2, WWWTest3, and WWWTest4 as virtual directories. Start and stop IIS server.
  12. Open Internet Explorer 3.02 and click Options on the View menu. Then click Advanced and select "Warn before accepting cookies." Browse to http://<servername>/ WWWTest3. The Application and Session variables should say "Cows Eat Cow Food!" (NOTE: If the error "800a01a8" Object required: Response appears, Refresh the page.)

    Now click WWWRoot2 and they should read "Dogs Eat Dog Food!" Next click WWWRoot4 and they should read "Tony Drinks Good Wine!"

    Finally, click WWWRoot and they should say "Chickens Eat Chicken Food!" Since you navigated to the WWWRoot directory last, all session and application variables will be in sync.
  13. Close and open Internet Explorer 3.02 again and browse to http://<servername>/WWWTest3 Again the Application and Session variables should read "Cows Eat Cow Food!" Now click the WWWRoot directory and they read "Chickens Eat Chicken Food!" This is not too surprising, but when you click WWWTest4 they read "Tony Drinks Chicken Food!"
Notice that once the WWWRoot directory is browsed that cookies are nolonger set, thereby freezing the session variables and resulting theappearance that session state has been lost, but application variablescontinue to change.
References
For the latest Knowledge Base artices and other support information onVisual InterDev and Active Server Pages, see the following page on theMicrosoft Technical Support site:
Properties

Article ID: 173307 - Last Review: 02/24/2014 08:29:45 - Revision: 5.0

  • Microsoft Active Server Pages 4.0
  • Microsoft Internet Information Server 3.0
  • Microsoft Internet Information Services 5.0
  • kbnosurvey kbarchive kbprb kbstate kbwebserver KB173307
Feedback