Session Object |
One of the greatest challenges you face in constructing a full-featured web application is keeping track of user-specific information while a user navigates your site without asking her to identify herself at every request from the server. Among other pieces of information that you need to maintain are a user's identification, a user's security clearance if applicable, and, in more advanced applications, user preferences that allow you to customize your web site's look and feel in response to selections made by the user. The primary problem with maintaining user-specific information is limitations in the currently standard HTTP 1.0 protocol. Although HTTP 1.0 does provide a mechanism for persistent connections that allows you to maintain user identification and user-specific data, its utility is limited. Without getting into the technical details, the Hypertext Transfer Protocol 1.0 allows client browsers to send Keep-Alive messages to proxy servers. These messages basically tell the proxy server to maintain an open connection with the requesting client. However, these connection requests are often unrecognized by the proxy server. This problem in the proxy server results in a hung connection between the proxy server and the requested web server. In a nutshell, maintaining connections with web servers is prone to error and thus is unreliable in HTTP 1.0, still by far the protocol most commonly used by client browsers. Microsoft Internet Information Server's (and other web servers') solution to this problem is to use the HTTP Persistent Client State Mechanism—better known as cookies—to identify the user. IIS handles this mechanism through the use of the Session built-in object. The Session object represents the current user's session on the web server. It is user specific, and its properties and methods allow you to manipulate the information on the server that is specific to that user for the duration of that user's connection. This duration is defined as the time from the client's first request of a page within your web application until 20 minutes (20 minutes is a default value that can be changed—see the section "Timeout", later in this chapter) after the user's last request to the web server. A user session can be initiated in one of three ways: A user not already connected to the server requests an Active Server Page that resides in an application containing a GLOBAL.ASA file with code for the Session_OnStart event. A user requests an Active Server Page whose script stores information in any session-scoped variable. A user requests an Active Server Page in an application whose GLOBAL.ASA file instantiates an object using the <OBJECT> tag with the SCOPE parameter set to Session. Note that a user session is specific to a given application on your web site. In fact, it is possible to maintain session information for more than one application at a time if one application is rooted in a virtual directory that resides under the virtual directory designating another application. The web server identifies each user with a unique SessionID value. This SessionID variable is assigned to each user at the beginning of his session on the web server and is stored in memory on the web server. The SessionID is stored on the client by writing a cookie containing the SessionID to the user's machine. This cookie is sent to the server each time the user makes a request. To identify the user, the server retrieves the cookie and matches it up with a SessionID held in memory. In addition to the SessionID variable, you can store other information specific to individual users. You can initialize (or change) any session-level variable anywhere in any Active Server Pages script. To ensure that a session-level variable is initialized to a specific value, you can script code in the Session_OnStart event procedure in the GLOBAL.ASA file. This event procedure is fired when the user's session starts. The GLOBAL.ASA file (see Chapter 11) is a special file that you can code specific to each ASP application. This file's code is processed when the user session begins. As discussed earlier, the Session object is very important in maintaining information about individual users. You also can use the Session object to handle some of the special issues that are specific to non-English-speaking clients requesting information from your web site.

Comments/Troubleshooting |
One of the most important things that you need to keep in mind when using the Session object is its scope. Any information you store with session-level scope is in scope for the duration of the user's session in a given application. This is a fine point. For example, assume your code deals with a session-level variable that was defined in the context of the Search application on your web site. This application's virtual directory, /search, reflects the following physical directory:
    D:\www\apps\search
The current script, SearchStart.ASP, resides in this directory. Assume that you have initialized a session-level variable, strSearchPref, in this script. Now the user moves to another application script, ContribMain.ASP, that resides in a separate application whose virtual directory, /contrib, reflects the following physical directory:
    D:\www\apps\contrib
If this user does not return to a script in the virtual directory encompassing the Search application within 20 minutes (or whatever the session duration is set to), the strSearchPref session-level variable value is reset. This is an important source of errors in complex web applications. A user session's session-level variables expire when the session ends, even if the time spent away from the application was spent in applications on the same web site. One way to avoid this problem is to nest applications. For example, you can place the /contrib virtual directory underneath the search directory, as reflected in the following path:
    D:\www\apps\search\contrib
Using this configuration, all requests to the contribution application's virtual path, /contrib, remain in the context of the search application. I've noted that you can change the default length of time after which a user session ends. Why would you want to do this? There are two possible reasons. The first is that you want to save the user's session information for longer than 20 minutes. For example, you may know beforehand that a user will leave your site for more than 20 minutes and then return. The second possibility is that you want to terminate the user's session information sooner. For example, say you know your users do not stay connected to your site for very long and you want to minimize the impact on server memory consumption that saving session information in memory consumes. See the section "Timeout", later in this chapter, for how to set this information differently from the default. All of this session-level information storage is based on the use of cookies sent to the client and then sent back to the server. What if the user has cookies turned off or is using an older browser that does not support the use of cookies? Well, if you are using Windows NT or Basic Authentication, you can identify the user from the LOGON_USER element of the Request object's ServerVariables collection. From this information, you can retrieve user-specific data from a database or text files on the server. If you are not using Windows NT or Basic Authentication, you will likely not be able to identify the user. In the past, you could use a user's IP address as an identifier, but with dynamically generated IP addresses using DHCP and firewalls, the IP address should be considered useless for the purpose of user identification.

CodePage |
Session.CodePage (= intCodePageValue)
Specifies or retrieves the code page that will be used by the web server to display dynamic content in the current script. A code page is a character set containing all the alphanumeric characters and punctuation used by a specific locale.
Parameters
intCodePageValue An unsigned integer corresponding to a specific character set installed on the server. Setting the CodePage property will cause the system to display content using that character set. The following table lists only a few of the possible valid values for this parameter:
CodePage Value | Language
932 | Japanese Kanji
950 | Chinese
1252 | American English (and most European languages)
Example
    <%

    ' In the following code, assume that the original code
    ' page setting is 1252 for American English. The
    ' example demonstrates the use of the CodePage property
    ' of the Session object to temporarily set the character
    ' set to Chinese so the text sent to the browser uses the
    ' Chinese character set:
    Dim uintOrigCodePage
    Dim uintChineseCodePage

    uintChineseCodePage = 950
    uintOrigCodePage = Session.CodePage

    Session.CodePage = uintChineseCodePage
    %>
    ' +-----------------------------------------------------------+
    ' | This text is sent to the client browser using the         |
    ' | Chinese character set.                                    |
    ' +-----------------------------------------------------------+
    <%

    ' Remember to reset your CodePage property if you don't want
    ' the rest of of the text created and placed into the HTML
    ' stream to be displayed using the new character set.
    Session.CodePage = uintOrigCodePage

    %>
Notes
Remember that, by default, Active Server Pages uses whatever character set you set for the script page using the CODEPAGE directive (see Chapter 11). Setting the CodePage property overrides this only for text sent to the browser. Script text is still communicated between ASP and your script or your script and ActiveX components using the same character set declared using the CODEPAGE directive.

LCID |
Session.LCID (= intLCID)
The locale represents a user preference for how certain information is formatted. For example, some locales have dates formatted in the Month/Day/Year format. This is the standard U.S. locale. Each locale is identified by that locale's unique LCID, or locale ID. This code is defined in the operating system. You can set the locale identifier for your script's content using the LCID property of the Session object. The LCID property represents the valid locale identifier that will be used to display dynamic content to the web browser.
Parameters
intLCID A valid 32-bit locale identifier.
Example
    <%

    ' The following code demonstrates the use of the LCID property
    ' to temporarily set the locale identifier to Standard French.

    Dim intOrigLCID
    Dim intFrenchLCID

    intFrenchLCID = 1036
    intOrigLCID = Session.LCID

    Session.LCID = intFrenchLCID
    %>
    ' +-----------------------------------------------------------+
    ' | This text sent to the client browser will be formatted    |
    ' | according to the rules set by the locale identifier for   |
    ' | Standard French. For example, dates would be formatted    |
    ' | using the Day/Month/Year format, instead of the U.S.      |
    ' | standard Month/Day/Year.                                  |
    ' +-----------------------------------------------------------+
    <%

    ' The next line resets the LCID property:
    Session.LCID = intOrigLCID

    %>
Notes
Similar to the CodePage property in syntax, the LCID property allows you to set the formatting rules for times and dates, and it also sets rules for alphabetizing strings. If you use the ASP LCID directive, you are setting the locale identifier for the script's environment on the server. The Session.LCID property uses this value as a default. If you wish to send string or date/time information to the client using different formatting rules, you must set the LCID property of the Session object. However, doing so has no impact on how the strings and date/time values are formatted internally to the script.

SessionID |
Session.SessionID
A read-only value that uniquely identifies each current user's session. This value is of data type Long and is stored as a cookie on the client machine. During a user's session, the user's browser sends this cookie to the web server as a means of identifying the user.
Parameters
None
Example
    <%

    ' The following code retrieves the current SessionID for
    ' a given user:

    Dim lngUserSessionId

    lngUserSessionId = Session.SessionID

    %>
Notes
The SessionID property is generated the first time a user requests a page from the web server. The web server creates a value for the SessionID property using a complex algorithm and then stores this value in the form of a cookie on the user's machine. Subsequently, each time the user requests a page from the web server, this cookie is sent to the server in the HTTP request header. The server is then able to identify the user according to her SessionID. The cookie is reinitialized only when the client restarts her browser or when the webmaster restarts the web server. Note that the SessionID cookie lasts on the client browser and is sent to (and recognized by) the web server until one of the two machines (client or web server) is restarted. This time period has nothing to do with the Timeout property of the Session object. For example, assume a user's session ends or is abandoned by using the Abandon method of the Session object. Then the user (without having restarted her browser) revisits the site. Assuming also that the web server has not been restarted since the end of the last session, the web server will start a new session for the user but will use the same SessionID, which is again sent to the web server as part of the HTTP request. This last point is important and is worth noting. Only if both the client browser and the web server applications have not been restarted can you assume a SessionID uniquely identifies a user. Do not use this value as a primary key, for example, as it is reset anytime either browser or server is stopped and restarted. Remember also that a browser that does not support cookies or that has cookies turned off will not send the SessionID as part of the HTTP request header. In this case, you must rely on some other method to identify users. You also can prevent the web application from using cookies by using the EnableSessionState preprocessor directive (for more details, see Chapter 11). To maintain information without using cookies, you could either append information from each request onto the QueryString or post the identifying information from a hidden form element on your page.

Timeout |
Session.Timeout (=intMinutes)
The length of time in minutes the web server will maintain a user's session information without requesting or refreshing a page. This value is set to 20 minutes by default.
Parameters
intMinutes The number of minutes for which the web server will maintain session information
Example
    <%

    ' The following code resets the Timeout property of the
    ' Session object from its default of 20 minutes to 5
    ' minutes.

    Session.Timeout = 5

    %>
Notes
The Timeout property is straightforward in use. You can set this property's value as high as you like, but note that the value for the Timeout property directly affects the memory consumption on the web server that each user session requires. Consider setting this number lower (as in the example) when your site's users visit for only brief periods. If, however, each page is visited for a longer period of time (for example, one page may provide a client-side scripted calculator), you may want to consider increasing this value. Note that, unlike most properties of the Session object, this property affects all user sessions, not just the current session. If you set the value of the Timeout property of the Session object to 120 minutes, every user's session information will remain in memory on the web server until 120 minutes after he last requests or refreshes a page.

Contents Collection |
    Session.Contents.Item("Pi") = 3.14
  Contains all of the variables and objects added with session-level scope through script (i.e., not through the use of the <OBJECT> tag). The Contents collection of the Session object, like other ASP collections, has the following properties: Item Retrieves the value of a specific member of the Contents collection. You specify which member using a string key (whose value is obtainable using the index through the Key property, described later in this section) or using an index number. For example, if you wish to initialize an element in the Contents collection with a value of Pi, you might use a line of code similar to the following:
      Session.Contents.Item("Pi") = 3.14
  In the preceding line of code, the desired element in the collection is specified using the key value "Pi." Thus initialized, you can then retrieve the value of this element of the Contents collection using the following line of code:
      dblMyVar = Session.Contents.Item("Pi")
  For reasons that will become clear in a moment, let's assume that this is the first element added to the Contents collection. You could also retrieve the value of an element in the Contents collection using its index in the collection rather than a key, as demonstrated in the following line of code:
      dblMyVar = Session.Contents.Item(1)
  Note that you use a 1 (one), not a (zero), to represent the first element in the Contents collection. This is a subtle point, since using a zero in this line of code will result in the variable dblMyVar being initialized with an undefined value. Unfortunately, this will not result in an error. It will result only in an improperly initialized variable:
      dblMyVar = Session.Contents.Item(0) ' WRONG.
  Item is the default property of the Contents collection and the Contents collection is the default collection of the Application object. This means that each of the following three lines of code is interpreted in exactly the same manner in your application:
      Session.Contents.Item("Pi") = 3.14
      Session.Contents("Pi") = 3.14
      Session("Pi") = 3.14
  Correspondingly, you would assume that the following three lines of code are also equivalent:
      Session.Contents.Item(1) = 3.14159
      Session.Contents(1) = 3.14159
      Session(1) = 3.14159
  However, this is only the case if the first element in the Contents collection has previously been defined using a key. Although not mentioned in the documentation that accompanies ASP, to use either of the preceding first two lines of code, the element must have been previously defined using a key. For example, assume you decide to add a second element to the Contents collection. You cannot initialize this element using either of the following lines of code:
      Session.Contents.Item(2) = 3.14159     ' WRONG.
      Session.Contents(2) = 3.14159          ' WRONG.
  Unfortunately, even this exception has an exception. You can use the following code to initialize a second variable:
      Session(2) = 3.14159
  When you consider these inconsistencies, it becomes quickly apparent that it is always safest to use a key rather than an index when referencing the value of a specific element in the Contents collection. Also, it is important to use a key when referring to a specific member of the Contents collection because that member's index may change. For example, suppose you have the following code in your application:
      Session("strFirstName") = "Arthur"
      Session("strMiddleName") = "Keyton"
      Session("strLastName") = "Weissinger"
  Assuming these variables are the first three added to the Contents collection, you could later refer to each using its index:
      strFirst = Session(1)
      strMiddle = Session(2)
      strLast = Session(3)
  However, if you use the Remove method, which completely removes a variable from the collection (see later in this chapter), to remove the strMiddleName variable, the index numbers will change:
      Session.Contents.Remove("strMiddleName")

      strFirst = Session(1)       ' Initializes to "Arthur"
      strMiddle = Session(2)      ' Initializes to "Weissinger"
      strLast = Session(3)        ' Initializes to Undefined.
  Key Represents the name of a specific element in the Contents collection. Remember from earlier that each element's value is represented by the Item property. Similarly, each element's name is represented by its Key property. If you do not know the name of a specific key, you can obtain it using its ordinal reference. For example, assume that you want to learn the key name for the third element in the collection and, subsequently, retrieve that element's value. You could use the following code:
      strKeyName = Session.Contents.Key(3)
      strKeyValue = Session.Contents.Item(strKeyName)
Count Returns the current number of elements in the collection. As with other ASP collections, you can retrieve the value of any field of the Contents collection through the use of the Item property. However, as in other places in this book, in the following examples, the syntax has been abbreviated so that it does not explicitly show the use of the Item property. For example:
    strSecurityCode = Session("UserSecurityCode")
is an abbreviated form of:
    strSecurityCode = Session.Contents.Item("UserSecurityCode")
For more information on the Item, Key, and Count properties of a collection, see the discussion in Section 4.2 in Chapter 4. Until ASP 3.0, items stored to the Contents collection remained in memory until the user session ended. ASP 3.0, on the other hand, adds two methods that allow members of the collection to be removed.

Remove |
Session.Contents.Remove(Key | Index)
Removes a specific member from the Contents collection. An addition in IIS 5.0, the Remove method allows you to remove from memory a specific variable from the Session's Contents collection without removing all the others. The Remove method is an important addition to the Contents collection because it allows for better memory control and cleanup. It allows you to remove from memory some of your collection's elements without abandoning the user's session. As discussed under the Item property of the Contents collection, it is very important to use a string key instead of an index when calling the Remove method. An element's index may change over the life of the application, and your call to Remove may lead to unpredictable results.
Parameters
Key A string variable that specifies the name of the specific member of the Contents collection to be removed. Index An integer variable that specifies the index of the specific member of the Contents collection to be removed.
Example
The following script removes two members of the Contents collection:
    <%
    ' This script assumes you have been "carrying around" various form
    ' variables for an online membership request form. The user has filled
    ' out the form, she has a username and is now a member. Now you would
    ' like to remove her form data which you stored in Session variables
    ' because it was convenient and the form's security had to be relatively
    ' high.
    strFirstName = Session("strFirstName")
    strLastName  = Session("strLastName")

    .
    .
    .
    Session.Contents.Remove("strFirstName")
    Session.Contents.Remove("strLastName")
    .
    .
    .
    %>

RemoveAll |
Session.Contents.RemoveAll
Removes all members from the Contents collection. An addition in IIS 5.0, the RemoveAll method allows you to remove from memory all Session-scoped variables without abandoning the Session. Like the Remove method, the RemoveAll method is an important addition to the Contents collection because it allows for better memory control and cleanup. It allows you to remove all Session-scoped variables without abandoning the session itself.
Parameters
None
Examples
The following script removes all members of the Contents collection:
    <%
    ' This script assumes you have been "carrying around" various form
    ' variables for an online membership request form. The user has
    ' filled out the form, she has a username
    ' and is now a member. Now you would like to remove her form data which
    ' you stored in Session variables because it was convenient and the
    ' form's security had to be relatively high.
    ' strFirstName = Session("strFirstName")
    ' strLastName  = Session("strLastName")

    .
    .
    .
    Session.Contents.RemoveAll
    .
    .
    .
    %>
The following script is the first of two ASP scripts that the user will visit (the first redirects the user's browser to the second). In this first script, the user's session-level variables are created (SessionVar1, SessionVar2, and SessionVar3).
    <HTML>
    <HEAD><TITLE>Session Contents Example Page1</TITLE></HEAD>
    <BODY>
    <%
    Dim strVar1
    Dim strVar2
    Dim strVar3

    strVar1 = "Session Variable 1"
    strVar2 = "Session Variable 2"
    strVar3 = "Session Variable 3"

    ' Each of the next three varieties of syntax
    ' are equivalent.
    Session.Content.Item("SessionVar1") = strVar1
    Session.Content("SessionVar2") = strVar2
    Session("SessionVar3") = strVar3

    Response.Redirect SessionPage2.asp
    %>
    </BODY>
    </HTML>
In this second script, we'll take a look at the current elements in the Contents collection of the Session object.
    <HTML>
    <HEAD><TITLE>Session Contents Example Page2</TITLE></HEAD>
    <BODY>
    <%
    Dim intContentsCount
    Dim strAppStatus
    Dim strKey
    Dim intCounter
    Dim objMyComponent
    Dim arystrNames( )

    intContentsCount = Session.Contents.Count
    strAppStatus = "Open"
    %>
    There are <%= intContentsCount %> items in the
    Session's Contents collection. <BR>
    <%
    For Each strKey in Session.Contents
    %>
       The next item in Session's Contents collection<BR>
       has <%= strKey %> as its key and
       <%= Session.Contents(strKey) %>
       as its value.<BR>
    <%
    Next

    ' Set the AppStatus item in the Contents collection.
    ' If this Session variable has been created before this,
    ' this line resets its value. If it has not been
    ' created, this line creates it.
    strAppStatus = "Page2...InProcess..."
    Session("AppStatus") = strAppStatus

    %>
    The first three elements of the Session's Contents
    collection are as follows: <BR>
    <%
    ' Retrieve the first three elements of the Contents
    ' collection.
    For intCounter = 1 to 3
    %>
       <%= Session.Contents(intCounter) %> <BR>
    <%
    Next
    %>
    A second trip through the first three items.
    <%
    ' This could just as accurately have been written
    ' like this:
    For intCounter = 1 to 3
    %>
       <%= Session.Contents.Item(intCounter) %> <BR>
    <%
    Next

    ' Add an object to the Contents collection, then use that
    ' object's PrintDoc method through the Contents collection.
    ' (NOTE: For more on the Server object, see Chapter 9.)

    '************************************************************
    ' If you try this script on your own, it will raise an error
    ' because of the lack of the Server component.
    '************************************************************
    Set objMyComponent = Server.CreateObject("MyComp.clsSpecial")
    Session ("objRef") = objMyComponent

    ' Call the object's method through the Contents collection.
    Session ("objRef").PrintDoc
    %>
    </BODY>
    </HTML>
Notes
If you add an object variable to the Session object's Contents collection, you can access that object's methods and properties through the Contents syntax. For example, the following code creates an instance of the MyServerComp object and then refers to its LastUpdated property:
    Dim datLastUpdated
    Set Session.Contents(objSessionMyObj)  =  _
       Server.CreateObject("MyCompanyDLL.MyServerComp")
    datLastUpdated = Session.Contents(objSessionMyObj).LastUpdated
When adding an array to the Contents collection, add the entire array. When changing an element of the array, retrieve a copy of the array, change the element, and then add the array as a whole to the Contents collection again. The following example demonstrates this point:
    <% Response.Buffer = True%>
    <HTML>
    <HEAD><TITLE>Session Array Example</TITLE></HEAD>
    <BODY>
    <%
    ' Create an array variable and add it to the
    ' Contents collection.
    ReDim arystrNames(3)

    arystrNames(0) = "Chris"
    arystrNames(1) = "Julie"
    arystrNames(2) = "Vlad"
    arystrNames(3) = "Kelly"

    Session.Contents("arystrUserNames") = arystrNames
    %>
    The second name in the User Names array is <BR>
    <%= Session("arystrUserNames")(1) %>
    <%

    ' Change an element of the array being held in the
    ' Contents collection. Use a different (new) array
    ' to temporarily hold the contents. Creating a new
    ' array is the safest way to work with Session
    ' arrays because most of the time you cannot be
    ' guaranteed how many elements are contained
    ' in a Session array created in another script.
    arystrNames2 = Session("arystrUserNames")
    arystrNames2(1) = "Mark"

    Session("arystrUserNames") = arystrNames2
    ' The second name is now Mark.
    %>
    <BR><BR>Now, the second name in the User Names array is <BR>
    <%= Session("arystrUserNames")(1) %><BR>
    <BR><BR><BR><BR><BR>
    NOTE: The first element of the Contents collection is still
    1, not 0 -- even though the first element of the array in element 1
    ("arystrUserNames") is 0:<BR><BR>
    <%= Session.Contents(1)(0)%> <BR>
    </BODY></HTML>
Objects created in the GLOBAL.ASA file are not actually instantiated on the server until the first time a property or method of that object is called. If you intend to use a given object in a transaction using the ObjectContext object, do not give that object application or session scope. An object used in a transaction is destroyed at the end of the transaction, and any subsequent reference to its properties or calls to its methods will result in an error. You will notice that the Contents (and StaticObjects) collection for the Session object is very similar to the Contents collection of the Application object. Although the Contents collection is the default collection of the Session object, there is one unusual behavior that differentiates it from the Contents collection of the Application object: You cannot retrieve an item directly from the Session object, because your implicit references to the Contents collection (the Session object's default collection) and the Item method (the collection's default value) cannot be resolved successfully. Suppose you have the following code:
    <HTML>
    <HEAD><TITLE>Strange Behaviour</TITLE></HEAD>
    <BODY>
    <%
    Session.Contents.Item("Item1") = "SessionVar1"
    Session.Contents.Item("Item2") = "SessionVar2"
    Session.Contents.Item("Item3") = "SessionVar3"
    %>
    . . . [additional code]
Because the Contents collection is the default collection of the Session object, you can refer to Item2 using the following line of code:
    strNewVar = Session("Item2")
However, unlike the Contents collection of the Application object, you cannot refer to the same element using the following line of code. This line of code will either be ignored or will raise an error, depending on the variable you are trying to retrieve:
    strNewVar = Session(2)
However:
    strNewVar = Session.Contents.Item(2)
or:
    strNewVar = Session.Contents(2)
work just fine. I was unable to find this behavior documented anywhere, but I found it to be consistent on IIS and Personal Web Server.

StaticObjects Collection |
    strFirstObjName = _
       Session.StaticObjects.Key(1)
  Contains all of the objects with session-level scope that are added to the application through the use of the <OBJECT> tag. You can use the StaticObjects collection to retrieve properties of a specific object in the collection. You also can use the StaticObjects collection to use a specific method of a given object in the collection. The StaticObjects collection of the Session object, like other ASP collections, has the following properties: Item Represents the value of a specific element in the collection. To specify an item, you can use an index number or a key. Key Represents the name of a specific element in the collection. For example:
      strFirstObjName = _
         Session.StaticObjects.Key(1)
  retrieves the name of the first element in the StaticObjects collection of the Session object. Use the value of the Key property to retrieve the value of an element by name. For example, suppose the first element's name is objMyObject. The code:
      strKey = Session.StaticObjects.Key(1)
      Session.StaticObjects.Item(strKey).Printer = "Epson 540"
then sets the value of the Printer property of the objMyObject element in the StaticObjects collection of the Session object. Count Returns the current number of elements in the collection. As with other ASP collections, you can retrieve the value of any field of the StaticObjects collection through the use of the Item property. However, as in other places in this book, in the following examples, the syntax has been abbreviated so that it does not explicitly show the use of the Item property. For example:
    strPrinterName = Session.StaticObjects("objMyObj").Printer
is an abbreviated form of:
    strPrinterName = Session.StaticObjects.Item("objMyObj").Printer
For more information on the Item, Key, and Count properties of a collection, see the discussion in Section 4.2 in Chapter 4.
Example
    ' < FROM GLOBAL.ASA >
    ' This code resides in the GLOBAL.ASA file at the
    ' root of the current application. The following
    ' <OBJECT> tag is only processed once for the current
    ' application.
    ' See Chapter 11 for more details on the GLOBAL.ASA file.

    <OBJECT RUNAT=Server
    SCOPE=Session
    ID=AppInfo1
    PROGID="MSWC.MyInfo">
    </OBJECT>

    <OBJECT RUNAT=Server
    SCOPE=Session
    ID=AppInfo2
    PROGID="MSWC.MyInfo">
    </OBJECT>

    ' <>

    <%
    ' The following code initializes the AppInfo1 component.
    ' This initialization code can reside anywhere.
    AppInfo1.PersonalName = "Gertrude Stein"
    AppInfo1.PersonalAddress = "233 Main Street"

    AppInfo2.PersonalName = "David Davidson"
    AppInfo2.PersonalAddress = "19A West Avenue"

    ' The following code uses the StaticObjects collection
    ' of the Session object to retrieve the value
    ' of the PersonalName property of both AppInfo1 and AppInfo2.
    For Each objInfo In Session.StaticObjects
    %>
       The personal name is <BR>
       <%= Session.StaticObjects(objInfo).PersonalName%>
    <%
    Next
    %>

    There are <%= Session.StaticObjects.Count %> items
    in the Session's StaticObjects collection.
Notes
The Session object's StaticObjects collection allows you to access any given object instantiated with session scope through the use of an <OBJECT> tag. Objects instantiated using Server. CreateObject are not accessible through this collection. The StaticObjects example in the IIS 5.0 documentation by Microsoft suggests that if you iterate through this collection, you will be able to reference each object's properties. This is somewhat misleading, as it suggests that the collection actually represents all the properties of the objects rather than the objects themselves. If you want to access the properties or methods of objects in the StaticObjects collection, you must use the dot operator outside of the parentheses around the Key, followed by the property or method name, as demonstrated here:
    <%= Session.StaticObjects(objInfo).PersonalName%>
This line of code works because Session.StaticObjects(objInfo) returns a reference to the objInfo object. Objects created in the GLOBAL.ASA file are not actually instantiated on the server until the first time a property or method of that object is called. For this reason, the StaticObjects collection cannot be used to access these objects' properties and methods until some other code in your application has caused them to be instantiated on the server. If you intend to use a given object in a transaction using the ObjectContext object, do not give that object application or session scope. Objects used in transactions are destroyed at the end of the transaction and any subsequent reference to their properties or calls to their methods will result in an error.

Abandon |
Session.Abandon
Releases the memory used by the web server to maintain information about a given user session. It does not, however, affect the session information of other users. If the Abandon method is not explicitly called, the web server will maintain all session information until the session times out.
Parameters
None
Example
The following script allows the user to click on a link that will redirect his browser to a page that will clear his session variables:
    <HTML>
    <HEAD><TITLE>Session Abandon Example Page1</TITLE></HEAD>
    <BODY>
    Click <A HREF = "/SessionAbandonPage2.asp">here</A> to reset your user preferences.
    </BODY>
    </HTML>
The following script actually clears the session variables:
    <HTML>
    <HEAD><TITLE>Session Abandon Example Page2</TITLE></HEAD>
    <BODY>
    <%

    ' The following code abandons the current user session.
    ' Note that the actual information stored for the current
    ' user session is not released by the server until the
    ' end of the current Active Server Pages.

    Session.Abandon

    %>
    Your user preferences have now been reset.
    </BODY>
    </HTML>
Notes
If you make heavy use of the Session object's Contents collection, the Abandon method can come in very handy. Suppose, for example, that you have many different user preferences saved as session variables and, as in the example, you want to remove them all and allow the user to select all new ones. Without the Abandon method, you would have to remove each variable from the Contents collection by hand—a slow and laborious prospect if you have several variables. The Abandon method allows you to remove them all in one line of code. The Abandon method is actually processed by the web server after the rest of the current page's script is processed. After the current page's processing is complete, however, any page request by the user initiates a new session on the web server. In the following example, the session variable intUserAge is available to your script until the end of the page. The Abandon method does not remove the variable from memory until the end of the page:
    Session("intUserAge") = 23
    Session.Abandon
    [...More Code...]
    ' The current line successfully retrieves the value of
    ' intUserAge.
    intAgeCategory = CInt(Session("intUserAge") / 10)
    [...End of Script. Session information is removed from web memory now...]

Session_OnEnd |
Session_OnEnd
Triggered when the user's session times out or when your scripts call the Abandon method of the Session object. The OnEnd event procedure, if it exists, resides in the GLOBAL.ASA file for the application that contains the requested page.
Parameters
None
Example
    <SCRIPT LANGUAGE = "VBScript" RUNAT = Server>

    Sub Session_OnEnd

       ' If the user has a search results recordset open, close
       ' it:
       If IsObject(adoRSResults) Then
          Set adoRSResults = Nothing
       End If

    End Sub

    </SCRIPT>
Notes
In the code for the OnEnd event procedure, you have access only to the Application, Server, and Session objects. Most important, you have no access to the Response object or Request object, and, for this reason, you cannot redirect the client or send cookies to (or receive cookies from) the client machine. One of the possible uses of the OnEnd event is to write information concerning the user to a log file or other text file on the server for later use. If you intend to do this, there are several important points you must remember. First, before you can save any information, that information must be saved to a session variable because, as mentioned earlier, you do not have access to the Request object, which is the most common source of user information. The following code demonstrates one possible method of storing a session-level variable:
    <SCRIPT LANGUAGE = "VBScript" RUNAT = Server>

    Sub Session_OnEnd

       ' Assume that SessionVar1 contains some user-preference
       ' information.

       ' It is not important that you understand exactly what is
       ' happening in the following code (you can learn more about
       ' File objects in Chapter 19). Just suffice it to say
       ' that these lines of code write the value of the
       ' SessionVar1 Session variable to the text file
       ' UserPref.txt.
       Set fs = Server.CreateObject("Scripting.FileSystemObject")
       Set f = fs.GetFile("d:\UserPref.txt")
       Set ts = f.OpenAsTextStream(ForAppending,_
                        TristateUseDefault)
       ts.Write Session(SessionVar1)
       ts.Close

       ' Note that more often than not, if you want to save this
       ' information to the server at the end of a user's session,
       ' it may very well be more efficient to store it to a
       ' database than to a text file. However, the general
       ' principal (of storing Session variable information in
       ' the OnEnd event) is similar.

    End Sub

    </SCRIPT>
Note that you cannot use the AppendToLog method of the Response object, because the Response object is unavailable. In addition, if you intend to write directly to the web server's hard drive, you must know the physical path of the file to which you want to write. This is because, although you do have access to the Server object, you cannot use its MapPath method in the OnEnd event (for more information about the MapPath method, see "MapPath" in Chapter 9).

Session_OnStart |
Session_OnStart
Triggered any time a user who does not already have a session instantiated on the web server requests any page from the server. The code in the OnStart event of the Session object, if it exists, is processed before any code on the requested page. The OnStart event procedure, if it exists, resides in the GLOBAL.ASA file for the application that contains the requested page.
Parameters
None
Example
    <SCRIPT LANGUAGE = "VBScript" RUNAT = Server>

    Sub Session_OnStart

       Dim strSiteStartPage
       Dim strCurrentPage
       Dim timUserStartTime
       Dim strUserIPAddress
       Dim strUserLogon

       ' Use the OnStart event to initialize session-level
       ' variables that your scripts can use throughout the
       ' the duration of the user's session.
       Session("timUserStartTime") = Now( )
       Session("strUserIPAddress") = _
               Request.ServerVariables("REMOTE_ADDR")

       ' Use the OnStart event to redirect the client if
       ' she attempts to enter the site from somewhere
       ' other than the site's home page.
       strCurrentPage = Request.ServerVariables("SCRIPT_NAME")
       strSiteStartPage = "/apps/home/startpage.asp"

       If StrComp(strCurrentPage, strSiteStartPage, 1) Then
          Response.Redirect(strSiteStartPage)
       End If

       ' You can also use the OnStart event of the Session
       ' object to assess user security access from the very
       ' beginning of the user's session. Note this code requires
       ' use of either the Basic authentication or Windows
       ' NT Challenge Response access control on the web server.
       strUserLogon = Request.ServerVariables("LOGON_USER")
       [...Code to Determine Security Level...]

    End Sub

    </SCRIPT>
Notes
If the client's browser does not support cookies or if the user has manually turned cookies off, the Session_OnStart event is processed every time the user requests a page from the site. No session is started or maintained. Like the OnEnd event, one of the possible uses of the OnStart event is to write information concerning the user to a log file or other text file on the server for later use. If you intend to do this, note that you cannot use the AppendToLog method of the Response object, and if you intend to write directly to the web server's hard drive, you must know the physical path of the file to which you want to write. This is because, although you do have access to the Server object, just as in the OnEnd event of the Session object, you cannot use the MapPath method of the Server object in the Session_OnStart event.