PRB: Nested Virtual Roots Can Lose Session State
ID: Q173307
|
The information in this article applies to:
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
CAUSENOTE: 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'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.
This behavior is by design.
MORE INFORMATIONSteps to Reproduce Behavior
- Configuration: In Microsoft Internet Service Manager, "Enable Default
Document" in the Directories tab needs to include "Default.asp."
- 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.
- 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>
- 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=<LINK TYPE="GENERIC" VALUE="http://<%=Request.ServerVariables("SERVER_NAME")%>/WWWTest2/>_">http://<%=Request.ServerVariables("SERVER_NAME")%>/WWWTest2/>_</LINK>
Click here to go to WWWTest2</A><BR>
<A
HREF=<LINK TYPE="GENERIC" VALUE="http://<%=Request.ServerVariables("SERVER_NAME")%>/WWWTest3/>_">http://<%=Request.ServerVariables("SERVER_NAME")%>/WWWTest3/>_</LINK>
Click here to go to WWWTest3>/A><BR>
<A
HREF=<LINK TYPE="GENERIC" VALUE="http://<%=Request.ServerVariables("SERVER_NAME")%>/WWWTest4/>_">http://<%=Request.ServerVariables("SERVER_NAME")%>/WWWTest4/>_</LINK>
Click here to go to WWWTest4>/A><BR>
</BODY>
</HTML>
- 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>
- 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>
- 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>
- 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>
- 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>
- 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>
- 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.
- 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.
- 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/
Additional query words:
Keywords : kbASP kbVisID kbWebServer kbGrpASP kbiis400 kbiis500
Version : winnt:
Platform : winnt
Issue type : kbprb
|