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
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 %>
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.
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.
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.