asp tutorials, asp.net tutorials, sample code, and Microsoft news from 15Seconds
Data Access  |   Troubleshooting  |   Security  |   Performance  |   ADSI  |   Upload  |   Email  |   Control Building  |   Component Building  |   Forms  |   XML  |   Web Services  |   ASP.NET  |   .NET Features  |   .NET 2.0  |   App Development  |   App Architecture  |   IIS  |   Wireless
 
Pioneering Active Server
 Power Search





Active News
15 Seconds Weekly Newsletter
• Complete Coverage
• Site Updates
• Upcoming Features

More Free Newsletters
Reference
News
Articles
Archive
Writers
Code Samples
Components
Tools
FAQ
Feedback
Books
Links
DL Archives
Community
Messageboard
List Servers
Mailing List
WebHosts
Consultants
Tech Jobs
15 Seconds
Home
Site Map
Press
Legal
Privacy Policy
internet.commerce














internet.com
IT
Developer
Internet News
Small Business
Personal Technology

Search internet.com
Advertise
Corporate Info
Newsletters
Tech Jobs
E-mail Offers

HardwareCentral
Compare products, prices, and stores at Hardware Central!

Avoid the Pitfalls of Sessions with the LookupTable
By Brian Reagan
Rating: 2.5 out of 5
Rate this article


  • email this article to a colleague
  • suggest an article

    Introduction


    You’re four pages into a five-page form and the phone rings. It’s someone important, so 20 minutes go by before you return to your form. When you return, you click to go back one page and, uh oh, the data’s gone. Damn session timeouts!
    We’ve all been there. In fact, I recently ran into the same thing on a multipage form. Though it didn’t surface during acceptance testing, some users in the field were filling out the forms over the course of hours, not minutes. The application’s data loss wasn’t winning a lot of fans.

    Well, the options for retaining data across pages, and over time, led down a few obvious paths. Cookies looked promising; the appeal of retaining a nondatabase-oriented replica of the field data was definitely a plus. The drawback, however, centered on user behavior: some field users were notorious for “tinkering” with their browser settings. The Dictionary object allows users to reference data with a name (as opposed to an index reference of an array), which was perfect for form fields NAME/VALUE pairs, but it was failing with the sessions. And, of course, the option of building a server-side component to handle the data persistence was looking mighty appealing1.

    Around this time (mid-March), Microsoft released the specs on the new MSDN online, particularly their use of a nifty Dictionary object replacement called the LookupTable. This new object provides hash table functionality similar to the VBScript dictionary; however, it is populated from text files. It’s also theadsafe in Application or Session scope. All of a sudden, I had access to a component that would combine the physical storage appeal of cookies with the speed and reference ability of the dictionary object.

    For more information on the LookupTable Component, visit the following site: http://msdn.microsoft.com/msdn-online/msdnchronicles2.asp

    So, I went to work and, inside of a day, I had a working prototype. And thanks to the diligent efforts of Jyothi Nagaraj and Catherine Okite, two developers in my group, we were able to apply these enhancements to the production application in a few short weeks.

    What follows is basically that prototype: a sample three-page form that illustrates the fundamentals – instantiating the LookupTable object(s), populating the text files from a form page, and retrieving text file values into a lookup object. For simplicity, I have not included field validation or database posting.

    Figure 1 : LookupTable Example - Sample Workflow

    First Things First: global.asa

    We need to create the object in global.asa – in this case, one object for each page of the form. Why one per page? Managing the files and objects is made a lot easier this way, especially with a lot of back-and-forth navigation.

    
    
    <OBJECT ID=newFRM1 PROGID="IISSample.LookupTable" RUNAT=SERVER SCOPE=SESSION></OBJECT>
    <OBJECT ID=newFRM2 PROGID="IISSample.LookupTable" RUNAT=SERVER SCOPE=SESSION></OBJECT>
    <OBJECT ID=newFRM3 PROGID="IISSample.LookupTable" RUNAT=SERVER SCOPE=SESSION></OBJECT>
    
    
    
    Wait a minute, I thought you said we’d avoid sessions?

    Bear with me for a moment. We do, in fact, avoid the session timeout pitfall. But, we have to use sessions here since each user should fill out a separate and unique form (with a corresponding separate and unique LookupTable). To that end, we also need to generate a unique number that will identify one person’s form from another. You might use the actual session ID or an auto-incrementing component. I use a simple counter in global.asa (see sample code for one method of generating this number).

    Trust me. This session stuff will become clear once we get to the form processing.

    The Form

    So, we launch the form from the page below. Notice that we populate the confirmation number from session but attach it to a hidden form field. Even if the person walks away for five hours before posting the form, the confirmation number is retained as part of the form. This is the last time we’ll use sessions. I’ve even added a session.abandon to prove it.

    Default.asp

    
    
    <%
    Option Explicit
    dim sConfNum
    sConfNum = session("sConfNum")
    %>
    <HTML>
    <HEAD><TITLE>Form Example - Launch Page</TITLE></HEAD>
    <BODY BGCOLOR="#FFFFFF">
    <FONT SIZE=+2><B>Take Me to the Sample Form</B></FONT><BR>
    <FORM ACTION="frmMain.asp" METHOD=POST>
    <INPUT TYPE=HIDDEN NAME="sConfNum" VALUE="<%= sConfNum %>">
    <INPUT TYPE=SUBMIT VALUE="Launch Form >>">
    </FORM>
    <% session.abandon %>
    </BODY>
    </HTML>
    
    
    
    The form itself is nothing special. It’s a simple three-pager that passes confirmation number, page number, navigation direction (sDir), and next/previous page for navigation (sPgNav) as hidden fields. Notice, however, the VALUE references for the input fields. We’re referencing the LookupValues in the newFRMx objects corresponding to the field names. The LookupTable, like Dictionary, doesn’t fail on blank or null values. So, we’re safe to reference lookups that haven’t yet been filled with data. You can see the entire page in the sample code.

    Figure 1 : The Form

    FrmMain.asp (code snippet)

    
    
    First Name:<BR>
    <INPUT TYPE="TEXT" NAME="txtFNAME" 
    VALUE="<%= newFRM1.LookupValue("txtFNAME") %>"><BR><BR>
    
    Last Name:<BR>
    <INPUT TYPE="TEXT" NAME="txtLNAME" 
    VALUE="<%= newFRM1.LookupValue("txtLNAME") %>"><BR><BR>
    
    E-mail Address:<BR>
    <INPUT TYPE="TEXT" NAME="txtEMAIL" 
    VALUE="<%= newFRM1.LookupValue("txtEMAIL") %>"><BR><BR>	
    
    
    
    
    
    

    The Form Post

    The fun begins once you submit the form. First, we retrieve our hidden page fields:

    
    
    dim sPg, sPgNav, sConfNum, sDir
    
    sPg = request("sPg")			‘what page did we come from
    sPgNav = request("sPgNav")		‘what page are we going to
    sDir = request("sDir")			‘are we going next or previous
    sConfNum = request("sConfNum")	‘what is the confirmation number
    
    
    
    In this example, we’re only saving when proceeding to “next,” so we must check the direction found in the sDir variable.
    
    
    if sDir = "FORWARD" then			‘ did we hit NEXT
    	call WriteChanges(sConfNum,sPg)	' generate text file
    else
    	call LoadValues(sConfNum,sPgNav)	‘ go get text file	
    end if
    
    
    
    The WriteChanges subroutine generates our text file from which our LookupTable object will be populated. We pass in both the confirmation number and current page number to generate a text file that will have the following name: pgX_YYYYY.txt (where X = page number and YYYYY = confirmation number). In the example code, a directory called txtForms holds all text files.
    
    
    Sub WriteChanges(sConfNum, sPg)
    	Dim objFSO, objFile, strFile, item
    
    	strFile = "pg" & CStr(sPg) & "_" & sConfNum & ".txt"		‘create page name
    	strFile =  Application("strFormsPath") & strFile		‘generate full path
    
    	Set objFSO = CreateObject("Scripting.FileSystemObject")	
    	Set objFile = objFSO.OpenTextFile(strFile,2,True)		‘open for writing and
    									‘create as needed
    	
    	for each item in request.form
    		objFile.WriteLine item & "," & request(item)		‘name,value pairs
    	next
    	objFile.Close
    	call LoadFormValues(sConfNum,sPg)				
    End Sub
    
    
    
    The last line of the WriteChanges subroutine calls the second subroutine to load the values from the newly created text file.
    
    
    	call LoadFormValues(sConfNum,sPg)				
    
    
    
    This subroutine is similar to WriteChanges because it works from the text file and application path. Since we have separate LookupTable objects for each page, however, the subroutine must make sure it’s matching the appropriate Lookup (in this case newFRM1) and text file (pg1_ConfNumber.txt).
    
    
    Sub LoadFormValues(sConfNum,sPg)
    	Dim objFSO, frmPage, frmPath, frmResult
    	
    	frmPage = "pg" & CStr(sPg) & "_" & sConfNum & ".txt"		‘get filename
    	frmPath =  Application("strFormsPath") & frmPage		‘get path
    	Set objFSO = CreateObject("Scripting.FileSystemObject")
    	if objFSO.FileExists(frmPath) then				‘is it there?
    		select case sPg					‘if so, load lookup
    			case "1"
    				frmResult = newFRM1.LoadValues(frmPath,0)						case "2"
    				frmResult = newFRM2.LoadValues(frmPath,0)	
    			case "3"
    				frmResult = newFRM3.LoadValues(frmPath,0)	
    		end select
    	end if
    End Sub
    
    
    
    The LookupTable.LoadValues method is used to load the text file. The second parameter (0) indicates that this is a text file with string/string key/value pairs on each line (you can use string/string, string/integer, integer/string, or integer/integer as you’d like). By adding 10 to this second parameter, you may also instruct the LookupTable to ignore duplicate keys.
    
    
    	frmResult = newFRM1.LoadValues(frmPath,0)	
    
    
    
    Finally, we redirect to the next (or previous) page in our form.
    
    
    response.redirect "frmMain.asp?sPg=" & sPgNav & "&sConfNum=" & sConfNum 
    
    
    
    And we’re done. When we navigate back to page one, the values are loaded directly from the LookupTable object. It’s fast, simple code, and if something crashes and burns, there’s still a text file on the server that holds the form data.

    The Magic

    And of course, the nice thing about having a server-resident text file with your form data is that, assuming you provide the confirmation number, your form data can be retrieved. The following variation on the LoadFormValues function provides a “Return to Saved Form” option.

    FrmGet.asp

    
    
    <%@ LANGUAGE="VBSCRIPT" %>
    <%
    Option Explicit
    Dim objFSO, frmPage, frmPath, frmResult, sConfNum, i
    %>
    <!--#include file="frmValues.inc"-->
    <%
    sConfNum = Trim(request("sConfNum"))
    for i = 1 to sMaxPage
    	frmPage = "pg" & CStr(i) & "_" & sConfNum & ".txt"
    	frmPath =  Application("strFormsPath") & frmPage
    	Set objFSO = CreateObject("Scripting.FileSystemObject")
    	if objFSO.FileExists(frmPath) then
    		select case i
    		case "1"
    			frmResult = newFRM1.LoadValues(frmPath,0)	
    		case "2"
    			frmResult = newFRM2.LoadValues(frmPath,0)	
    		case "3"
    			frmResult = newFRM3.LoadValues(frmPath,0)	
    		end select
    	end if
    next
    response.redirect "frmMain.asp?sPg=1&sConfNum=" & sConfNum
    %>
    
    
    

    Don’t Look Now: More Benefits

    One of the interesting elements about the LookupTable that Microsoft discusses in their MSDN implementation is the ability to wrap XML in the text files. For our purposes, this is fodder for future discussions. But, given the success of the implementation, we’re eager to investigate additional functionality offered by the LookupTable component.

    Source Code

    Unzip the following code and set up a Web site in IIS.
    http://15seconds.com/files/990701.zip

    About the Author

    Brian Reagan has worked in IT consulting and database systems design for over a decade. He's spent the last five years focused on web development, delivering high-profile internet sites and web-enabled corporate applications. Now, he's driving enterprise architecture and deployment at EMC Corporation, where he manages the IS Web Services group. At night he's focused on changing his newborn's diapers.

  • Rate This Article
    Not HelpfulMost Helpful
    1 2 3 4 5
    Supporting Products/Tools
    ASP Session Manager
    ASP Session Manager works by inserting 2 lines of code at the top of your ASP script and have the session serialize itself to any DBMS. There are three licenses available, ranging from a single binary to an enterprise ISP license with source code.
    [Top]
    SA-Session Pro
    Web farm getting out of control? You need scalability! SA-SessionPro is a simple, yet very powerful means of making your ASP application persistent--share and save information on a per-user, per-application, per-server, or per network basis. SA-Session is like the built in Session object that comes with the IIS Server, except it allows developers more flexibility. It has the ability to store information without expiration and the ability to preserve session state across multiple machines in a web farm.
    [Top]
    SessionFarm
    SessionFarm is an Active Server Pages component that allows you to manage session state on multiple servers in a web-farm. SessionFarm utilizes the built-in IIS Session object which means you don't have to learn new methods and objects. The IIS Session object is stored on either a file-share or a SQL database using optimized stored procedures.

    SessionFarm requires no rewriting of your existing code and works by supplementing the existing IIS Session.

    For code samples, see http://www.groat.com/sessionfarm/implement.asp.

    [Top]
    Other Articles
    Mar 7, 2001 - Are Session Variables Satan's Spawn?
    A seemingly innocent Inquiry has sparked a member of the 15Seconds discussion list to answer with a sermon on the evil nature of Session Variables.
    [Read This Article]  [Top]
    Dec 30, 1999 - Using Hidden FRAMES to Hold Data or Maintain State
    Hidden frames allow users to maintain almost any kind of data, and maintain state easily and reliably. Mark Burnham's article uses a shopping cart scenario to show simple ways to read and write data, and call functions from a hidden frame. Visible frames can be loaded with virtually anything, but these hidden frames will always be there, holding data until it's needed.
    [Read This Article]  [Top]
    Dec 23, 1999 - How to Detect If Cookies Are ON
    Mark Burnham offers a quick and easy way to check if your browser accepts cookies. If it does, then you're clear to use session variables when writing ASP scripts. Just follow the sample code to learn how to copy a form and compare SessionIDs.
    [Read This Article]  [Top]
    Jan 14, 1999 - Easy Application State Securely
    This article by Dmitry Khanine shows how to make your web site 100-percent secure when maintain your application state.
    [Read This Article]  [Top]
    Jan 8, 1998 - Maintaining State
    In this issue we will discuss two built in states of the Internet Information Server, session and application. We will also continue where we left off with the Nov 08, 1997 - Sharing Cookies Across Domains Issue, and show how to maintain session state across multiple servers in a web farm. Also discussed, will be user state and the use of personalization to maintain user state.
    [Read This Article]  [Top]
    Mailing List
    Want to receive email when the next article is published? Just Click Here to sign up.

    Support the Active Server Industry


    The Network for Technology Professionals

    Search:

    About Internet.com

    Legal Notices, Licensing, Permissions, Privacy Policy.
    Advertise | Newsletters | E-mail Offers