This article may contain URLs that were valid when originally published, but now link to sites or pages that no longer exist. To maintain the flow of the article, we've left these URLs in the text, but disabled the links.


MIND


This article assumes you're familiar with Active Server Pages and VBScript.
Download the code (3KB)

The Lost QueryString: Maintaining State with Active Server Pages
Bill Kropog

New ASP developers often shy away from integrating ASP and standard HTML features. But QueryString can help your ASP apps pass data and maintain state easily.
Active Server Pages (ASP) has to be one of the best ideas Microsoft has ever come up with (other than Windows®, of course). Although ASP has many powerful features, one of its highlights is the ability to maintain state among the pages of a Web application. Despite these strengths, Web developers using ASP find themselves in the unfamiliar position of trying to manage session and application-wide variables on their Web pages. In this article, I'll navigate through some ways to make ASP an easier to use and more effective tool.
      It's not difficult to get overwhelmed by ASP when you first dive in. All those new toys and cool features—many of which seem too good to be true—take a little getting used to. New ASP developers tend to stay away from a tight integration of ASP features with tried-and-true, standard HTML.
      One of these useful HTML-based features is the QueryString, a powerful ally for building organized and efficient ASP applications. The QueryString passes data in a concise, well-organized manner from page to page. In many cases, it can help you maintain state more effectively than using Session variables.

The Lure of ASP
      It is important to understand how Active Server Pages are processed and how information is sent to the client browser. First, the page must be assembled. If it contains any Server Side Includes (SSIs), these are fetched and placed where they belong. SSIs are a powerful tool for reusing code for site navigation bars, script blocks, and so on. Because SSIs are processed first, they can also contain server-side script. Once the page is completely assembled at the server, it is processed as if it were straight HTML.
      At this point, the page is checked for server-side script (VBScript or JScript™). Server-side script provides the intelligence to your pages and makes them, in essence, a real application. This script is set off by the <% and %> tags so that the server knows which code to process. Any code not contained within the <% and %> tags is sent to the client browser as part of the regular HTML page (unless that particular line has been subjected to conditional scripting).
      When you make full use of server-side scripting, your pages can really come alive. You can tailor the content and presentation of your site according to the information that server-side scripting provides. Content based on the time of day, background colors based on the season, advertisements based on a user's previous visits, and reading and writing to a database are all adjustments you can easily make with ASP.
      The five built-in ASP objects give developers tremendous control over their pages. Unfortunately, many ASP newbies are too quick to fall in love with the Session object as the cure-all for maintaining state among pages. When I first started using ASP, I had Session variables for everything, but I soon realized that much of what I was doing was completely unnecessary, not to mention confusing. It's easy to forget that QueryString is still available. You remember QueryString; it's the thing that comes after the question mark in a URL. With all those Session variables flying around, it's very easy to see how the QueryString could get lost in the shuffle.
      One of the cool features of ASP is that you can tap into the QueryString collection just like the Form collection. In fact, just change the <FORM> tag's method to GET instead of POST and you'll be passing the form's information with the QueryString. Whether you're using the QueryString or the Form collection, you can write an ASP on the receiving end to grab the data and do whatever you please with it.

The Impossible Task
      So, you may wonder, why put information in the QueryString if the Form collection does the job just fine? I used to ask that same question until I ran into a snafu when working on an intranet project. The client, a national bank, wanted to share optically-stored documents among all its locations spanning two states. The far back end of the application was to be handled by a proprietary device that would fetch documents upon request. My ASP-based application would talk to this device and search its contents, which would be indexed on a remote database.
      The bank wanted their customers to enter search criteria on one page and to have the results presented in a separate two-frame page. The bottom frame would contain the results of the query, while the top frame would have column headers plus an abbreviated version of the search form. The idea was that as the user scrolled through the search results, the column headers would always remain in view, making it easier to read the data. The additional search form would be conveniently in view, not buried at the bottom of 100 or more items.
      The trick was to get the information from the main search form to a child frame of a two-frame document. This sounds easy enough, right? Just create a simple form using the POST method, which calls the container document of the <FRAMESET>. That <FRAMESET> document would then call the documents that fill its resulting frames. And each document contained within one of those frames would reveal the contents of the Form collection. Follow me? To test it, all you have to do is call

 <%Response.Write(Request.Form)%>
and your Form collection should be displayed.
      Well, it's not there. The code's right—everything checks out—but no Form collection data. Where did it go?
      Would you believe I spent over an hour trying to figure this one out? The answer is very simple and, admittedly, quite obvious. I'll show you a sample application to help demonstrate what's going on. To run the application, simply create a Web (or a subdirectory of an existing Web) and put the ASP documents in it. Open Microsoft® Internet Explorer and browse to Sender.asp (see Figure 1).
      Sender.asp is the form-containing document that collects data from the user and sends it to another page. In this example, I've included two forms on the page so I can compare them. One form uses the POST method and the other uses GET. Frames.asp (see Figure 2) is the <FRAMESET> container document. It calls Header.asp (see Figure 3) and Receiver.asp (see Figure 4) in their respective frames. Receiver.asp is the document that will display the form data coming from Sender.asp.
      Clicking the left Submit button (see Figure 5) sends the form's data using the POST method, which most developers use by default anyway. But the data never gets to Receiver.asp. According to the code, the Form collection should have been displayed in the browser window, but it wasn't (see Figure 6). Click Do it again! to return to the first page. This time, click the Submit button on the right; its form uses the GET method, passing data in the QueryString, whereas the POST method uses the document's header. The result this time is that you see the form's data listed as it should be (see Figure 7), compliments of QueryString.
Figure 5: Sender.asp
Figure 5: Sender.asp
Figure 6: No Data with Forms
Figure 6: No Data with Forms
Figure 7: QueryString Passed Correctly
Figure 7: QueryString Passed Correctly

      When a Form or QueryString collection is sent to a page, it dies with that page. Since a <FRAMESET> container document is just a regular HTML page, any Form or QueryString collection stops with that page and is not passed along to the documents called by the resulting frames. To get the information to those frames, you have to give it a helping hand—and what better way to pass a string of data than with the QueryString?
      Okay, all you Session variable lovers are probably thinking that you could create Session variables for everything to solve the problem. But that would get messy, and it uses more system resources than is really necessary. A much simpler way is to use the GET method in your form, like I did in the sample app. All you have to do is catch and then pass the QueryString to the desired frame in Frames.asp (see Figure 2).
      Notice that I put the whole QueryString from Sender.asp into the QueryString sent by Frames.asp to its child frames. I used an implicit write <%=…%> after the question mark at the end of the URL, taking extra care not to forget the equal sign. Keep in mind that ASP will put the interpreted results of that write method into the HTML the browser gets. This is what I call the hand off. Technically, you could keep passing the QueryString from one document to another if the need ever arises.
      Receiver.asp receives the QueryString just as if Sender.asp sent it. In fact, Receiver.asp doesn't care which page sends the QueryString as long as the data in it is correct (see Figure 8). If you're concerned about users being able to see the QueryString in the Address window of the browser, there's a simple workaround: change the form's method back to POST, which means the form's information is once again passed in the Form collection rather than the QueryString.
Figure 8: QueryString Pass-along
Figure 8: QueryString Pass-along

      In Frames.asp, you can change <%=Response.QueryString%> to <%=Response.Form%> and the Form collection's data will be put into the resulting QueryString. Remember, you'll still have to read the data as a QueryString collection in Receiver.asp, but users will not be able to see it in the Address window. There's really little difference between the two methods. In the first method, the life of the data looks like this:

 Form Collection Æ QueryString Æ QueryString
In the latter method, it looks like this:

 Form Collection Æ Form Collection Æ QueryString
      You don't have to use <FRAME> documents to take advantage of the QueryString. Rather than creating multitudes of those tempting little Session variables, try to pass the information with the URL using the QueryString. It makes debugging a lot easier in multiple-page applications if you narrow down the number of global variables you use. It's tempting to create Session variables for stuff that only has to travel one or two pages. By passing this short-lived data in the QueryString, you literally don't have to worry about tracking it down later when something goes wrong. Plus, you can usually see it in the Address window of the browser for instant debugging.
      In some of your high-end applications you will want to be careful about what you expose in the Address window, but for those small to mid-sized applications, the QueryString is a good old friend who still knows a few tricks.

Changing Multiple Frames
      Another neat trick to use with frame documents is switching the content of two frames at the same time. It's true that calling a new <FRAMESET> document containing both new frames would achieve the same effect, but doing so has some drawbacks. First, the entire browser window goes blank while the parent <FRAMESET> document is called, and then you still have to wait for each of the individual frames to load. That's three documents to wait for. What if you could cut that number down to two? Try this simple JScript function:


 function Linker(URL){
 window.parent.frames[0].location=URL;
 }
      Instead of calling a new parent document, you'll simply replace the contents of each existing frame using just one hyperlink. The HREF part of the hyperlink takes care of the contents of one frame, and the Linker function takes care of the other. Put the Linker function in a script block in the <HEAD> of the document. Make a call to it in the onclick event of the hyperlink, specifying the name of the document you want to put into the other frame:

 <a href= "frame2.htm" onclick= "Linker('frame1.htm');">Go Now</a>
      In the Linker function, you're basically backtracking up the frame hierarchy to dictate the content of one particular frame. The frame is determined by the frames[0] portion of the function. JScript indexes the frames of a Web page from left to right and top to bottom, starting with 0 as the first frame. In a two-frame document, the top frame would be 0 and the bottom would be 1.
      The sample app's Receiver.asp has an extra hyperlink called Change two frames! to demonstrate this function. Clicking that link calls Newdoc.htm into the bottom frame and Newhead.htm into the top frame (see Figure 9). Using the Linker function, Newdoc.htm has a hyperlink to return both frames to their original content. Don't forget that you can also pass bookmarks to the Linker function in case you only want to point the contents of one frame to a different location on the same HTML page.
Figure 9: Change two frames!
Figure 9: Change two frames!

      The Linker function makes dual-frame switches much smoother than the conventional method of calling a whole new <FRAMESET>. Site visitors don't feel like they've made such a huge leap because you are reducing the number of new documents that have to be called and one page usually loads first.
      It is possible to do frames well. If a <FRAMESET> layout clearly communicates your information to the visitor, then why not use it? The two tips discussed in this article make frames more functional and a lot more pleasing to the eye. Remember, the best use of frames is when the visitor forgets you're using them.

From the August 1998 issue of Microsoft Interactive Developer.