Friday, July 06, 2007

Application variables

Application variables were under-used on my site, but not for long! I realized recently that a list box that I was populating with data from my database changed very rarely.
So why should every visitor to the site have to cause an identical database query? The simple answer is to take advantage of Application variables. Think of the "Application" in this case being IIS - the server. Once set, Application variables are available to all pages on your site. But it's important to remember that they are gone forever if the server is restarted.
Using Application variables is easy - all you need are statements like:
// to set the data
Application ( 'Data' ) = 'something';

// to use the data
Response.Write ( 'data is ' + Application ( 'Data' ) );
 
Part 2

A simple function to store HTML

In the earlier example of populating a list box from a recordset I created a function to execute the query, and store the HTML in Application variables for easy and very efficient re-use:
// ============================================
// put infrequently changing data into application variables
// ============================================
function GetListFromApp ( sSQL, sName)
{
   var sHTML;

   // connect to database
   DBInitConnection ( );

   // get HTML from Application variable
   // and if empty...
   if ( ! ( sHTML = Application ( sName ) ) )
   {
      //...get records from database
      DBGetRecords ( sSQL );

      // make up HTML <select> tag
      sHTML = '<select name="' +sName + '">';

      while ( !oRecordSet.EOF )
      {
         sHTML += '<option>' + oRecordSet ( 0 ) + '</option>';      
         oRecordSet.moveNext ( );
      }

      sHTML += '</select>';

      // set the Application variable
      Application ( sName ) = sHTML;
   }

   // release database connection
   DBReleaseConnection ( );

   return sHTML;
}
To use it to store a list box containing all your professors names, do this:
// form tag posting to itself
Response.Write ( '<form action="' + Request.ServerVariables ( 'SCRIPT_NAME' ) + '" method="post">' );

// a list box containing professors - only
// does database query once
Response.Write ( 'Department code: ' + GetListFromApp ( 'SELECT Name FROM Professors', 'prof' ) );
 
Part 3

Counting visits and page views

Another example where I use Application variables is to implement the fun count of active users seen in the top right corner of every page.
This involved a file not discussed yet on this site - global.asa. This file contains four functions that are called by the server at specific times, as documented in the file shown below.

global.asa

<script language=JavaScript runat=server>

// ============================================
// this function is called when the first user visits the page after the server
// has been rebooted. also called when this file is changed.
// ============================================
function Application_OnStart ( )
{
   // you dont need to lock the Application object
   // in this function - but remember to do it elsewhere...
   //   Application.Lock ( );

   // number of users currently on the site
   Application ( 'ActiveUsers' ) = 0;
   // number of users on the site today
   Application ( 'UsersToday' ) = 0;
   // number of pages viewed today
   Application ( 'PagesToday' ) = 0;
   // has the count been restarted today?
   Application ( 'NewToday' ) = 1;
   // number of headers viewed ever
   Application ( 'HeadersViewed' ) = 0;
   // number of footers viewed ever
   Application ( 'FootersViewed' ) = 0;
   // initialize new stuff in utils/Init.asp
   Application ( 'BrandNewDay' ) = 1;
   // a list of IP addresses that have clicked an ad
   Application ( 'ClickFromIP' ) = '';
   // counters for rotating banners
   Application ( 'CurrentTopBanner' ) = 0;
   Application ( 'CurrentSideBanner' ) = 0;
   Application ( 'CurrentAffiliate' ) = 0;

   // remember todays date
   var d = new Date;
   Application ( 'Today' ) = d.getDate ( );

   // Application.Unlock ( );
}

// ============================================
// this function is called when the server shuts down
// ============================================
function Application_OnEnd ( )
{
}

// ============================================
// this function gets called whenever a new user visits the site. note that
// session variables require the client browser to accept cookies
// ============================================
function Session_OnStart ( )
{
   // you must lock the global Application object
   // when writing to it - ok to read without lock
   Application.Lock ( );

   // one more active user
   Application ( 'ActiveUsers' )++;

   // is it a new day?
   var d = new Date;
   var nDate = d.getDate ( );

   if ( Application ( 'Today' ) == nDate )
   {
      // same day, so increment users today
      Application ( 'UsersToday' )++;
   }
   else
   {
      // new day, so restart count
      Application ( 'Today' ) = nDate;
      Application ( 'UsersToday' ) = 1;
      Application ( 'PagesToday' ) = 1;
      Application ( 'BrandNewDay' ) = 1;

      // and say I havent restarted today
      Application ( 'NewToday' ) = 0;
   }

   Application.Unlock ( );
}

// ============================================
// this function gets called after a user session times out - by default
// after 20 minutes. or you can call Session.Abandon ( )
// ============================================
function Session_OnEnd ( )
{
   // you must lock the global Application object
   // when writing to it - ok to read without lock
   Application.Lock ( );

   // one less active user
   Application ( 'ActiveUsers' )--;

   Application.Unlock ( );
}
</script>
 
Part 4
Then to display the data in the header of every page I use this code in utils/Header.asp:
// lock the application so I can increment page counter
Application.Lock ( );
Application ( 'PagesToday' )++;
Application.Unlock ( );

// display the data
var nUsers = Application ( 'ActiveUsers' ) - 0;
var nUsersToday = Application ( 'UsersToday' ) - 0;
var nPagesToday = Application ( 'PagesToday' ) - 0;
var bRebootToday = Application ( 'NewToday' ) - 0;

Out ( nUsers + ' active user' + ( (nUsers==1) ? '!' : 's' ) + '<br>' );
Out ( nUsersToday + ' visitor' + ( (nUsersToday==1) ? '' : 's' ) + ' today<br>' );
Out ( nPagesToday + ' page' + ( (nPagesToday==1) ? '' : 's' ) + ' today<br>' );

Out ( '<a href="Application.asp">' );

if ( bRebootToday )
   Out ( '(only part of today)' );
else
   Out ( 'how is this done?' );
Incidentally, for those of you not familiar with C or JavaScript, the "?:" syntax in the source code...
Response.Write ( (nUsers==1) ? '!' : 's' );
...is shorthand for writing this:
if ( nUsers == 1 )
   Response.Write ( '!' );
else
   Response.Write ( 's' );


Fussy? Opinionated? Impossible to please? Perfect. Join Yahoo!'s user panel and lay it on us.

0 Comments: