Application and Session Variables

The Application and Session objects can be used to store values that are global either to a particular user (the Session) or to all users (the Application). Within the onStart events, we can initialize these variables. We can also store new variables, or change existing values, in the code inside any other ASP page.

Initializing variables is very important, especially with a language like VBScript that uses Variants. Imagine the following code in a page:

Response.Write("The current value is: " & Session("MyValue"))

This places the contents of the Session variable MyValue in the page. The only problem with this code is if the variable has not been initialized. What we get is:

The current value is:

Any Variant (the only data type available in VBScript) that has not been assigned a value is said to be Empty. Because we are dumping the variable as its default type, we get nothing. The best way to solve this type of problem is either assign a default value to it, or examine the variable using the IsEmpty() function. Here's how we could use IsEmpty():

varTheValue = Session("MyValue")
If IsEmpty(varTheValue) Then varTheValue = "* Undefined *"
Response.Write("The current value is: " & varTheValue)

Alternatively, we can set any default value we like in the Session_onStart event, so that we have a value ready for access in that session:

Sub Session_OnStart
  Session("MyValue") = 42
End Sub

Counting Sessions

An immediately obvious use of this technique is to count how many sessions have occurred during the current application. All we do is use a variable stored in the Application object, which is then available to all sessions:

Sub Application_OnStart
  Application("NumVisitors") = 0
End Sub

Now, in Session_onStart, we can increment the value for each new session:

Sub Session_OnStart
  Application.Lock
  Application("NumVisitors") = Application("NumVisitors") + 1
  Application.Unlock
End Sub

Them we can drop it into the 'welcome' page with a few lines of code:

<% Application.Lock %>
<H3> Your are visitor number <% = Application("NumVisitors") %> </H3>
<% Application.Unlock %>

Storing Array Variables

As we briefly mentioned in Chapter 2, we have a problem when storing arrays in a Session or Application object, which maintain all values as Variants. The following example shows how we can get round this limitation:

'Create and initializing the array
Dim MyArray()
ReDim MyArray(5)
MyArray(0) = "hello"
MyArray(1) = "some other string"
'Store the array in the Session object
Session("StoredArray") = MyArray
'Now retrieve the array from the Session object
LocalArray = Session("StoredArray")
LocalArray(1) = "there"
...
'and then store the updated one back again
Session("StoredArray") = LocalArray
...

We create the array MyArray()and ReDim it to hold five elements. Then we assign strings to the elements 0 and 1,and simply assign the array directly to a variable StoredArray in the Session object. We've effectively converted our array of strings into a variant array, and stored it in a single Variant in the Session.

Later in the same script, or in another request in the same session, we can retrieve the array using LocalArray = Session("StoredArray"), then access it as normal using the indexes. You might be tempted to believe that instead of assigning the array to a single Session variable, we could access it using Session("StoredArray")(1) = "there", but this is not the correct method. It will result in loss of data.

The Application and Session objects' variables are implemented as collections, however we should not actually access them in this way—it is not documented or recommended. Neither is it possible to store references to any of the Active Server Pages built-in objects—for example the statement Set Session("MyRequest") = Request is not legal.

Reference Counting with the Application Object

You'll recall we suggested earlier that the Application_onEnd event might not be fired until the Web server is stopped. So what happens to the global objects that are stored within the Application object? They are kept alive and available all of the time. If you have a resource that you don't want to be kept in memory for days on end, when the application is not in use, the following code solves the problem, and demonstrates some of the ways of using the Application and Session objects:

Sub Session_OnStart
  Application.Lock
  If IsEmpty(Application("Object")) Then
    Set Application("Object") = Server.CreateObject("global.connection")
    Application("ObjectCount") = 0
  End If
  Application("ObjectCount") = Application("ObjectCount") + 1
  Application.Unlock
End Sub
Sub Session_OnEnd
  Application.Lock
  Application("ObjectCount") = Application("ObjectCount") - 1
  If Application("ObjectCount") = 0 Then
    Set Application("Object") = Nothing
  End If
  Application.Unlock
End Sub

The technique we use in this code is called reference counting. Notice that the Application events are not used, but the Application object is. All the events are those that occur for each Session. The technique, however, is simple enough. At the start of each Session, we only create an instance of the object we want (in this case a fictitious "global.connection") if it does not already exist. At the end of each Session, we destroy the object if no-one else is using it. If you like, it's the old 'last one out turn off the lights' trick.

How It Works

This code works by keeping a count of the number of users that are using the application at any one time, storing this count in a global variable called ObjectCount. If this is zero, or does not exist, the Session_onStart code creates the object and stores the reference to it in the Application object as a variable called Object, and it's then available to all users. At the same time, it sets the value of ObjectCount to zero, in case it didn't actually exist—in other words if this was the first ever session to use the application.

The next step is to increment the value of ObjectCount, so that it reflects the number of current sessions. If the object already exists when a Session starts, and the Object variable does reference an object when this session begins (i.e. it's not Empty), the code will just increment ObjectCount without creating a new instance of the object.

The Session_onEnd code, which runs for each Session as it ends, just has to decrement the value of ObjectCount, and it can then tell how many other sessions are still active. If this is zero it can destroy the object by setting its reference variable to Nothing.

Notice that we've again used the Application object's Lock and Unlock methods before changing the values of any of its variables. Failing to do this can cause all kinds of problems by allowing more than one session to access the values at the same time. This concept is called concurrency, and we'll look at the implications that arise from it next.

© 1997 by Wrox Press. All rights reserved.