PRB: Nested Virtual Roots Can Lose Session State

Last reviewed: December 11, 1997
Article ID: Q173307
The information in this article applies to:
  • Microsoft Active Server Pages, versions 1.0, 1.0b

SYMPTOMS

When browsing to a child virtual root that is nested within a parent virtual root, and then navigating 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). On the other hand, 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's like ASP does not check for
      nested virtual roots.

Internet Service Manager allows users to set up directories and their subdirectories as virtual roots. This creates a situation where there are virtual roots with nested virtual roots, which themselves can contain Global.asa files with Application_OnStart and Session_OnStart subroutines.

Here is an example directory structure with each virtual directory containing a Global.asa:

   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

Once the user browses to the root directory, which in a default installation is the wwwroot directory, the SessionID is created and does not change even when navigating to other nested virtual roots, but the Application-scoped variables continue to change each time the users browses a page in a different virtual root. This causes the Application variables to appear to be lost.

However, if the root directory is the last directory navigated to and has never been visited before, then each nested directory maintains its own SessionID 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, but 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 designing Web projects. Instead use one virtual root for each Web project containing the Global.asa for that project.

STATUS

Microsoft is researching this problem and will post new information here in the Microsoft Knowledge Base as it becomes available.

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=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>
          <A
          HREF=http://<%=Request.ServerVariables("SERVER_NAME")%>/WWWTest4/>_
          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>
          -------------------------
    
    

  10. Open Internet Service Manager, right-click the WWWService and select the Directories tab. Click the Add button and add WWWTest2, WWWTest3, and WWWTest4 as virtual directories. Start and stop IIS server.

  11. 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 on WWWRoot2 and they should read "Dogs Eat Dog Food!" Next click on WWWRoot4 and they should read "Tony Drinks Good Wine!"

    Finally, click on the 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.

  12. 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 no longer set, thereby freezing the session variables and resulting the appearance that session state has been lost, but application variables continue to change.

REFERENCES

For the latest Knowledge Base artices and other support information on Visual InterDev and Active Server Pages, see the following page on the Microsoft Technical Support site:

   http://support.microsoft.com/support/vinterdev/


Keywords          : VIASP
Technology        : kbInetDev
Version           : WINDOWS NT:1.0,1.0b
Platform          : NT WINDOWS
Issue type        : kbprb


================================================================================


THE INFORMATION PROVIDED IN THE MICROSOFT KNOWLEDGE BASE IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND. MICROSOFT DISCLAIMS ALL WARRANTIES, EITHER EXPRESS OR IMPLIED, INCLUDING THE WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT SHALL MICROSOFT CORPORATION OR ITS SUPPLIERS BE LIABLE FOR ANY DAMAGES WHATSOEVER INCLUDING DIRECT, INDIRECT, INCIDENTAL, CONSEQUENTIAL, LOSS OF BUSINESS PROFITS OR SPECIAL DAMAGES, EVEN IF MICROSOFT CORPORATION OR ITS SUPPLIERS HAVE BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. SOME STATES DO NOT ALLOW THE EXCLUSION OR LIMITATION OF LIABILITY FOR CONSEQUENTIAL OR INCIDENTAL DAMAGES SO THE FOREGOING LIMITATION MAY NOT APPLY.

Last reviewed: December 11, 1997
© 1998 Microsoft Corporation. All rights reserved. Terms of Use.