|
In the context of Active Server Pages, an application is the sum of all
the files that
can be accessed through a given virtual directory and its subdirectories.
This ASP
application context is the same for all clients using the application.
For example, a
client from Thailand who requests pages from your /SearchApp virtual directory
is
accessing the same application as a second client from Sweden
who is
requesting pages from the same virtual directoryregardless of which
specific
web page within the virtual directory each is requesting.
Just as traditional standalone applications allow you to share information
throughout the application, so too do ASP applications. You can share
information
among all clients of a given ASP application using the Application object.
This
built-in object represents the ASP application itself and is the same
regardless of
the number or type of clients accessing the application and regardless
of what part
or parts of the application those clients are requesting.
The Application object is initialized by IIS the moment the first client
requests any
file from within the given virtual directory. It remains in the servers
memory until
either the web service is stopped or the application is explicitly unloaded
from the
web server using the Microsoft Management Console.
IIS allows you to instantiate variables and objects with application-level
scope.
This means that a given variable contains the same value for all clients
of your
application. You also can instantiate server-side objects with application-level
scope that likewise contain the same values for all clients. These application-level
variables and objects can be accessed and changed from the context of
any users
session and from any file within the current application.
As stated earlier, the Application objects initialization occurs
when the first user of
your application requests any file from within the virtual directory that
the ASP
application encompasses. This initialization can be thought of as setting
aside
memory for the given ASP application. The web server instantiates and
initializes
the Application object for you. However, you can customize this initialization
by
including code in a special optional file called GLOBAL.ASA. Although
I will
discuss this file in greater depth in Chapter 10, Preprocessing Directives,
Server-Side
Includes, and GLOBAL.ASA, it is worth presenting a brief overview here.
The GLOBAL.ASA file existsif it existsat the root of the physical
directory
mapped to by your ASP applications virtual directory. It is processed
every time a
new user requests a page from within the applications virtual directory.
This file
contains initialization code for both the users session and the
application itself. If
the user is not the first user, the application-specific sections of GLOBAL.ASA
are
not processed. If the GLOBAL.ASA file does not exist or does not contain
any
code, but the users request is the web servers first request
for files within a given
application, the web server still initializes the Application object.
However, the
web servers initialization involves only the dimensioning of memory
required for
the application.
The GLOBAL.ASA file provides a place for you to create variables and objects
that
have application-level scope. This section of the GLOBAL.ASA file represents
an
event procedure. The event is the OnStart event, and its event handler
is executed
when the application is started. Its important to note that although
the GLOBAL.ASA
file is processed for every user that makes a request, the Application
objects
OnStart event is executed for only the first user. (The OnStart and the
corresponding
OnEnd event procedures are covered in detail later in this chapter.)
Variables and objects with application-level scope have the same value
for all
users at all times during the life of the application. If one user requests
a page
containing code that changes an application-level variables value,
then that variables
value is changed for all users. This presents a problem: potentially,
two or
more users could attempt to change the value of the same application-level
variable
at the same time. Fortunately, ASP provides the Application objects
Lock and
Unlock methods to avoid conflicts in these situations. Just as you must
carefully
consider the ramifications of using global variables in a multithreaded
application,
you also must consider the ramifications of using variables with application-level
scope. Use application-level variables with care.
The properties, collections, methods, and events of the ASP Application
object are
outlined in the following box.
Comments/Troubleshooting
Application-level variables are, in effect, global variables for your
ASP application.
The use of globals in ASP applications should be viewed with as much skepticism
as the use of globals in traditional standalone applications, if not with
more. The
most important step is to painstakingly consider its scope before implementing
any
object or variable with application-level scope. There are very few instances
in
which using these ASP global variables is necessary.
With that warning, there are a few instances in which using application-level
variables
or objects is useful in creating functional ASP applications. One of the
most
important of these is maintaining application-specific statistics for
your web site.
Using application-level variables that are incremented at the beginning
of each
user session, for example, you could maintain a count of clients that
have used
your application. Although such web management tools as Microsoft Site
Server
perform similar tasks, their statistics are file specific, not application
specific.
Some ASP literature has suggested using application-level objects for
maintaining
open ActiveX Data Objects (ADO) database connections for all application
users.
(For more information on ADO, see Chapter 11, ActiveX Data Objects 1.5.)
This is
not a good use of application-level variables, since this approach prevents
ODBC
from pooling connections per individual pages.* However, you could use
an application-
level variable to maintain an application-specific connection string for
that
same database connection.
There is one trap that you should be aware of when considering the use
of application-
level variables and objects. Consider the following scenario. You have
two
physical directories: c:\inetpub\wwwroot\MainApp and c:\inetpub\wwwroot\
MainApp\SearchApp. These directories are mapped to the virtual directories
/MainApp and /SearchApp, respectively. You have, in effect, an application
within
an application. The first client requests a page within the c:\inetpub\wwwroot\
MainApp\SearchApp physical directory. Which initialization code will be
used to
initialize the Application objectthe code in the GLOBAL.ASA for
/MainApp or the
GLOBAL.ASA for /SearchApp? In this case the /SearchApp GLOBAL.ASA is the
one
processed. Until a file in /MainApp that does not exist in /SearchApp
is requested,
the GLOBAL.ASA file for /MainApp is not processed. If the two GLOBAL.ASA
files
define different sets of application-level variables, you have no way
of knowing
within your code which Application variables were properly initialized
without
testing them.
Application Object Summary
Properties
None
Collections
Contents
StaticObjects
Methods
Lock
Unlock
Events
OnStart
OnEnd
* ODBC connection pooling provides a method by which
ODBC connections can be reused
by successive users. Instead of creating a new connection each time a
client requests one, the
server attempts to reuse an already existing connection that is no longer
in use. If unused
ODBC connections reside in memory after a certain period of time (configured
in the MMC),
they are destroyed to free memory.
Finally, note that IIS now allows you to set ASP applications up in separate
memory spaces from each other and from the web server itself by simply
checking
an option on the Properties panel of a given virtual directory in IISs
Microsoft
Management Console. This ability is an important improvement in IIS. If
your ASP
application is running in a separate memory space from the web server
and a
server object in it (or the scripting engine itself) crashes, it will
not also crash the
web server or your other ASP applications.
Collections Reference
Contents Collection
Application.Contents(Key)
The Contents collection of the Application object contains all the application-level
scoped variables and objects added to the current application through
the use of
scripts (not through the use of the <OBJECT> tag).
Before examining how elements are added to the Contents collection, you
must
first understand the properties of the Contents collection. The Contents
collection
has three properties:
Item
Sets or retrieves the value of a specific member of the Contents collection.
You determine which specific member of the collection by using an index
number or a key. For example, if you wish to set the value of the first
element of the Contents collection, you could use a line of code similar
to the
following:
Application.Contents.Item(1) = 3.14159
Note that you use a 1 (one), not a 0 (zero), to represent the first element
in
the Contents collection. This is a subtle point, since using a zero in
your code
will not result in an error; it will simply be ignored.
The next point to note is that we could have set the value of this element
using a name instead of a number, as in:
Application.Contents.Item("PI") = 3.14159
The name of the element (in this case PI) is its Key property
(discussed next).
Item is the default property of the Contents collection, and the Contents
collection is the default collection of the Applications object. This
means that
each of the following three lines of code is interpreted in exactly the
same
manner in your application:
Application.Contents.Item(1) = 3.14159
Application.Contents(1) = 3.14159
Application(1) = 3.14159
as is each of these:
Application.Contents.Item("PI") = 3.14159
Application.Contents("PI") = 3.14159
Application("PI") = 3.14159
One final point: it is always safer to use the key rather than the index
when
referencing the value of a specific element in the Contents collection,
because
the index numbers for elements in the Contents collection begin from the
first
application-scoped variable value set by any user of your application.
With
application-scoped variables, determining which variable was set first
(aside
from those in the GLOBAL.ASA file) can be problematic.
As mentioned earlier, the values of the elements in the collection that
were
set in the Application_OnStart event in the GLOBAL.ASA file are set in
the
order in which they exist in the event procedures code.
Key
Represents the name of a specific element in the Contents collection.
Remember from earlier that each elements value is represented by
the Item
property. Similarly, each elements 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
elements value. You could use the following code:
strKeyName = Application.Contents(3)
strKeyValue = Application.Contents.Item(strKeyName)
If, on the other hand, you know that the third elements key name
is STATE,
you could simply use the following code to retrieve the value of that
element:
StrKeyValue = Application.Contents.Item("STATE")
Count
Represents the total number of elements in the Contents collection.
Notes
You can initialize application-level variables and thus add elements to
the
Contents collection in one of two ways. First, you can initialize Application
variables
in the Application_OnStart event procedure in the GLOBAL.ASA file, as
Example 4-1 illustrates.
Example 4-1: Initializing Application-Level Variables in GLOBAL.ASA
' <<<<<<<<<<<<<<< FROM GLOBAL.ASA
>>>>>>>>>>>>>>>>>>
' This code resides in the GLOBAL.ASA file at the
' root of the current application.
' See Chapter 10 for more details on the GLOBAL.ASA file.
Sub Application_OnStart
Application.Contents.Item(1) = "Georgia"
Application.Contents(2) = "Kentucky"
Application(3) = "Alabama"
Application.Contents.Item("STATE_FOURTH") = "California"
Application.Contents("STATE_FIFTH") = "Oregon"
Application("STATE_SIXTH") = "Washington"
End Sub
The code in Example 4-1 creates six application-scoped variables, thus
adding six
elements to the Contents collection. Note that these variables will be
instantiated
and initialized only at the start of the application, not upon every visit
to the site
by subsequent users. These variables maintain the same values unless another
script changes them for all pages and for all users.
You also can create application-scoped variables and thus add elements
to the
Contents collection inside any script on any page. Note, however, that
any variables
created in this manner are created and maintained across the whole
application and all its users. Example 4-2 illustrates this method of
initializing
application-scoped variables.
The code in Example 4-2 adds six more application-scoped variables to
the application.
Note that these variables will be reinitialized every time a user requests
the
page containing this code. To prevent this waste of processor power, it
might be
better to perform this initialization using code similar to the following:
<%
' A more efficient example of the creation of an
' application-scoped variable.
If IsEmpty(Application.Contents.Item(13)) Then
Application.Contents(13) = "Texas"
End If
%>
This code creates a 13th application variable for the current application
only if it
has not already been created.
The Contents collection supports the For Each and For
Next constructs
for iterating
the collection, as Example 4-3 demonstrates.
Example 4-2: Initializing Application-Level Variables in a Server-Side
Script
<%
' This code exists in the server-side section of a script
' on the web site.
Application.Contents.Item(7) = "Florida"
Application.Contents(8) = "Tennessee"
Application(9) = "Mississippi"
Application.Contents.Item("STATE_TENTH") = "New York"
Application.Contents("STATE_ELEVENTH") = "New Jersey"
Application("STATE_TWELFTH") = "Vermont"
%>
Example 4-3: Using For Each with the Contents Collection
<%
For Each strKey in Application.Contents
%>
The next item in Application's Contents collection<BR>
has <%= strKey %> as its key and
<%= Application.Contents(strKey) %>
Note, however, that the Contents collection does not support the Add or
Remove
methods that are common with most collection objects. This makes planning
imperative, since variables given application scope stay resident until
the web
server is stopped or the last users session times out.
If you add an object to the Applications Contents collection, make
sure that the
threading model for the object supports its use in an application scope;
use of the
free-threaded model is recommended.
* For more on the use of various threading models in
IIS server components, see Shelley Powers forthcoming book Developing
ASP Components, published by OReilly & Associates.
To access an application-scoped objects properties or methods, use
an extension
of the syntax you saw earlier for accessing the value of an application-scoped
variable,
as the following code fragment illustrates:
' In this example, assume you have an application-scoped Ad
' Rotator variable called MyAdRot.
' Accessing a property:
intBorder = Application.Contents("MyAdRot").Border
' Executing a method:
Application.Contents("MyAdRot").GetAdvertisement("Sched.txt")
If you intend to use a given object in a transaction using the Object-
Context 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.
When adding an array to the Application objects Contents collection,
add the
entire array as a whole. When changing an element of the array, retrieve
a copy of
the array, change the element, and then add the array to the Contents
collection as
a whole again. The code in Example 4-4 demonstrates this.
as its value.
<P>
<%
Next %>
* Free-threaded applications allow multiple user processes
to access the same instance of the
component simultaneously.
Example 4-4: Working with Arrays in the Contents Collection
<%
' Create an array variable and add it to Contents collection.
ReDim arystrNames(3)
arystrNames(0) = "Chris"
Example 4-3: Using For Each with the Contents Collection (continued)
StaticObjects
Application.StaticObjects(Key)
The StaticObjects collection contains all of the objects added to the
application
through the use of the <OBJECT> tag. You can use the Item property
(discussed
later) of the StaticObjects collection to retrieve properties of a specific
object in the
collection. You also can use the Item property of the StaticObjects collection
to
access a specific method of a given object in the collection.
You can add objects to this collection only through the use of the <OBJECT>
tag in
the GLOBAL.ASA file, as in the following example:
<OBJECT RUNAT=Server SCOPE=Application ID=AppInfo2
PROGID="MSWC.MyInfo">
</OBJECT>
You cannot add objects to this collection anywhere else in your ASP application.
The StaticObjects collection, like other ASP collections, has the following
properties:
Item
Returns a reference to a specific element in the collection. To specify
an item,
you can use an index number or a key.
arystrNames(1) = "Julie"
arystrNames(2) = "Vlad"
arystrNames(3) = "Kelly"
Application("arystrUserNames") = arystrNames
%>
The second name in the User Names array is
<%= Application("arystrUserNames")(1) %>
<BR>
<%
' Change an element of the array being held in the
' Contents collection.
ReDim arystrNames(3)
arystrNamesLocal = Application("arystrUserNames")
arystrNamesLocal(1) = "Mark"
Application("arystrUserNames") = arystrNamesLocal
' The second name is now Mark.
%>
Now, the second name in the User Names array is
<%= Application("arystrUserNames")(1) %>
<BR>
Example 4-4: Working with Arrays in the Contents Collection (continued)
Key
Returns the name of a specific element in the collection; the name is
assigned
by the ID attribute of the <OBJECT> tag. For example, you could
receive the
name of the first element in the collection like this:
objElement = Application.StaticObjects.Key(1)
Use the value of the Key property to retrieve the value of an element
by
name. For example, suppose the first object in the StaticObjects collection
is
named MyAdRotator. You could then use the following line of code to set
(or
retrieve) the value of the Border property of that object:
strKey = Application.StaticObjects.Key(1)
Application.StaticObjects.Item(strKey).Border = 0
Count
The current number of elements in the collection.
For more imformation on the Item, Key, and Count properties of a
collection, see the section on the Contents collection of the Application
object, earlier in this chapter.
Example
' <<<<<<<<<<<<<<< FROM GLOBAL.ASA
>>>>>>>>>>>>>>>>>>
' This code resides in the GLOBAL.ASA file at the root
' of the current application. The following <OBJECT>
' tag is processed only once for the current application.
' See Chapter 10 for more details on the GLOBAL.ASA file.
<OBJECT RUNAT=Server
SCOPE=Application
ID=AppInfo1
PROGID="MSWC.MyInfo">
</OBJECT>
<OBJECT RUNAT=Server
SCOPE=Application
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"
36 Chapter 4 Application Object
Methods Reference
ASP in a Nutshell: A Desktop Quick Reference, eMatter Edition
Copyright © 2000 OReilly & Associates, Inc. All rights
reserved.
' The following code uses the StaticObjects collection
' of the Application object to retrieve the value
' of the PersonalName property of both AppInfo1 and AppInfo2.
For Each objInfo In Application.StaticObjects
%>
The personal name is <BR>
<%= Application.StaticObjects(objInfo).PersonalName%><P>
<%
Next
%>
There are <%= Application.StaticObjects.Count %> items
in the Application's StaticObjects collection.
Notes
The StaticObjects collection allows you to access any object instantiated
with
application-level scope through the use of an <OBJECT> tag. Objects
instantiated
using the Server.CreateObject method are not accessible through this collection.
The nomenclature here can be a bit confusing. To reiterate: the StaticObjects
collection contains those server objects instantiated through the use
of the
<OBJECT> tag, not through the CreateObject method of the Server
object.
The StaticObjects example in the IIS 4.0 documentation by Microsoft suggests
that
if you iterate through this collection, you will be able to reference
each property.
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 in the preceding example.
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.
Do not give application or session scope to an object used in a transaction
using
the ObjectContext object. Objects used in transactions are destroyed at
the end of
the transaction, and any subsequent references to their properties or
calls to their
methods will result in an error.
Methods Reference
Lock
Application.Lock
The Lock method locks the Application object, preventing any other client
from
altering any variables values in the Contents collection (not just
those variables
you alter before calling the Unlock method). The corresponding Unlock
method is
used to release the Application object so other clients can again alter
the Contents
collection variable values. If you fail to use the Unlock method, IIS
will unlock the
variable automatically at the end of the current Active Server Pages script
or upon
script timeout,* whichever occurs first.
Parameters
None
Example
<%
' This script exists on the second page of a
' multipage ASP application, so that users may
' or may not visit it. The example shows how you could
' see how many visitors the page has had.
' Assume that TotalNumPage2 starts at 0.
' Lock the Application object.
Application.Lock
intNumVisits = Application.Contents("TotalNumPage2")
intNumVisits = intNumVisits + 1
Application.Contents("TotalNumPage2") = intNumVisits
' Explicitly unlock the Application object.
Application.Unlock
' NOTE: Using the PageCnt.DLL would be a more
' efficient manner of doing this.
%>
<HTML>
<HEAD><TITLE>Home Page</TITLE></HEAD>
<BODY BGCOLOR = #ffffcc>
Welcome to our homepage. You are client number
<%= Application.Contents("TotalNumPage2")%> to our site.
Thank
you for your patronage.
</BODY>
</HTML>
Notes
Any client connected to your web server can call a script that potentially
could
alter the value of a variable in the Application Contents collection.
For this reason,
it is a good idea to use the Lock and Unlock methods every time you reference
or
alter a variable in the Contents collection. This prevents the possibility
of a client
attempting to change a variables value when another client is resolving
that variables
value.
* The ASP script timeout is adjustable through the Properties page of
the web site using the
Microsoft Management Console. The default is 120 seconds.
Keep in mind that you cannot create a read-only variable by using a call
to the
Lock method without a corresponding call to Unlock, since IIS automatically
unlocks the Application object.
You do not have to call the Lock and Unlock methods in the Application_OnStart
event procedure (see this chapters Events Reference for more about
the
Application_OnStart event). The Application_OnStart event occurs only
once
regardless of the number of sessions that are eventually initiated. Only
the first
client request triggers the Application_OnStart event and, for that reason,
only that
client can alter the value of the specific Application variable. Also,
no other client
requests will be handled until the Application_OnStart code has completed.
Unlock
Application.Unlock
The Unlock method releases the application variables from a Lock method
call.
Once Unlock has been called, other clients can again alter the values
of the variables
in the Application Contents collection. If you call Lock and do not provide
a
corresponding Unlock, IIS will automatically unlock the variables in the
Application
Contents collection at the end of the current active server page or when
the
script times out, whichever comes first.
Parameters
None
Example
See the example for Application.Lock.
Notes
See the notes for Application.Lock.
Events Reference
OnEnd
Application_OnEnd
The Application_OnEnd event is triggered when the ASP application itself
is
unloaded from the web server (using the Microsoft Management Console)
or when
the application is inadvertently stopped for some reason (i.e., the web
service is
stopped on the web server). Application_OnEnd is called only once per
application.
The code for this event procedure resides in the GLOBAL.ASA file and is
processed after all other code in the file. It is in the code for the
Application_
OnEnd event that you will clean up after any application-scoped
variables.
Parameters
None
Example
' <<<<<<<<<<<<<<< FROM GLOBAL.ASA
>>>>>>>>>>>>>>>>>>
' This code resides in the GLOBAL.ASA file at the
' root of the current application. The following
' procedure is processed only once for the current
' application.
' See Chapter 10 for more details on the GLOBAL.ASA file.
<SCRIPT LANGUAGE="VBScript" RUNAT=Server>
Sub Application_OnEnd
' This code will run on the server when
' the application stops.
' This code saves the final count of an application
' use counter to a file.
Set filsysObj1 = _
CreateObject("Scripting.FileSystemObject")
Set tsObj1 = filsysObj1.CreateTextFile("c:\usrcount.txt", _
True)
tsObj1.WriteLine(Application.Contents("AppUserCount"))
tsObj1.Close
End Sub
</SCRIPT>
' <<<<<<<<<<<<<<<<<<<<<<<<<>>>>>>>>>>>>>>>>>>>>>>>>>
Notes
The use of the Application_OnEnd event is tricky. The Microsoft documentation
suggests that the OnEnd event is triggered when there are no longer any
active
sessions. However, this is not the case. Only when the web service is
interrupted
or when the administrator explicitly unloads the application from the
web servers
memory (using the MMC) is the OnEnd executed. You cannot assume that this
event will ever be called from your application without something going
wrong or
direct intervention on your part. This is yet another reason to very carefully
consider the implications before using application-level variables of
any kind.
You cannot use the Server object method MapPath (see Chapter 8, Server
Object,
for more on the Server object) to map a relative or virtual directory
to a physical
directory within the Application_OnEnd event procedure. Microsoft gives
no
reason for this limitation, though it is likely a security-related control.
OnStart
Application_OnStart
The Application_OnStart event is triggered when the first client request
is received.
Application_OnStart is called only once per application. The code for
this event
procedure resides in the GLOBAL.ASA file and is processed before any other
code
or object instantiation in the file.
Parameters
None
Example
' <<<<<<<<<<<<<<< FROM GLOBAL.ASA
>>>>>>>>>>>>>>>>>>
' This code resides in the GLOBAL.ASA file at the
' root of the current application. The following
' procedure is processed only once for the current
' application.
' See Chapter 10 for more details on the GLOBAL.ASA file.
<SCRIPT LANGUAGE="VBScript" RUNAT=Server>
Sub Application_OnStart
' This code will run on the server when
' the application starts.
' This code retrieves the last final user count
' and uses it to initialize an Application
' variable.
Set filsysObj1 = CreateObject("Scripting.FileSystemObject")
Set tsObj1 = filsysObj1.OpenTextFile("c:\usrcount.txt", _
True)
Application.Contents("AppUserCount") = tsObj1.ReadAll
tsObj1.Close
End Sub
</SCRIPT>
' <<<<<<<<<<<<<<<<<<<<<<<<<>>>>>>>>>>>>>>>>>>>>>>>>>
Notes
The Application_OnStart event procedure, if it exists, is the first code
run on the
server for a given Active Server Pages application. For this reason, it
is the best
place to initialize application-level variables. No other code in your
ASP application
is guaranteed to run.
Carefully consider the use of application-level variables. Every variable
with application
scope that you dimension and initialize in the Application_OnStart event
continues to take up memory on the server until the end of the application.
|