When State Doesn’t Look After Itself

The whole concept of Applications and Sessions requires the browser to accept and implement cookies. If it doesn't, then ASP is unable to maintain state information of any kind. We have to resort to the older methods of CGI programming.

How State Works in ASP

As we said earlier, the HTTP protocol is inherently stateless, and relies on cookies to be able to manage and recognize requests, and match them to the users. When ASP wants to establish a session, it sends the Set-Cookie HTTP header to the browser, to establish a unique user session ID and the path of the application it corresponds to—i.e. where the appropriate global.asa file resides:

Set-Cookie: ASPSESSIONID=LRUSDYXQMWRTNWEB; path=/TestApp

From our discussions of cookies in Chapter 2, you'll realize that this one doesn't expire until the browser is shut down. In theory, if the browser was to be left running for weeks on end, the cookie will remain current. But the Session object has a default Timeout of twenty minutes, and that point the Session is marked as having ended and any variables in it are destroyed.

The Un-expired Cookie Problem

The fact that a user's Session ID cookie may not have expired, while the matching Session on the server already has expired, raises an interesting question. What happens if that user comes back to our site again? The server will check the session ID in their cookie against the currently active sessions, and if it doesn't match will just create and initialize a new Session. The user then effectively 'goes back to the start'.

Of course, this assumes that the session ID will be unique for every user. If this isn't the case, the application might find itself with two users sharing a Session. We have to assume that Microsoft has thought of this, and that the session ID generator is sufficiently random to prevent it happening!

When the Cookie Jar is Empty

One problem that Microsoft cannot prevent is the situation where the session ID cookie our server sends is not supported by the browser, or not accepted by the user. Or more critically, it's possible for the server administrator to turn off the ability to maintain Sessions altogether by editing the registry. Now, the automatic state mechanism is not going to work, so we need an alternative plan.

We could use a system originally implemented in ASP, but then removed again, which added parameters to all the hyperlinks in the pages so as to pass on the session ID. We could emulate this, or just shunt the user off to a separate version of our site that worked without requiring state information. We could even throw them out altogether, though this may tend to discourage future visits...

Checking for Cookie Acceptance

But before we can do any of this, we need a way of determining whether or not the browser can support cookies, without causing havoc. Easy enough, we just use a default opening page that gets sent to every user, when they first enter the application. We could include a 'Welcome' graphic, like a real application's splash screen, or possibly some introduction to the site:

Here's the code that creates this page, with the important lines are highlighted:

<HTML>
<HEAD>
<META HTTP-EQUIV="REFRESH" CONTENT="5; URL=hellotest.asp"> 
<TITLE>Document Title</TITLE>
</HEAD>
<BODY>
<CENTER><IMG SRC="Welcome.gif"></CENTER>
<% On Error Resume Next
   Session("TestBrowser")="Hello" %>
</BODY>
</HTML>

The ASP code first turns off error checking, then stores a value in a Session level variable named TestBrowser. If the browser doesn’t support cookies, or if they're turned off, there will be no Session object and the code will fail—however there won't be an error message because of the On Error Resume Next. The real key to this page is the first highlighted line:

<META HTTP-EQUIV="REFRESH" CONTENT="5; URL=hellotest.asp"> 

Once the page has finished loading, the browser waits five seconds and then loads the page hellotest.asp—which contains this code, placed before the <HEAD> section:

<% On Error Resume Next
   If IsEmpty(Session("TestBrowser")) Then
     Response.Redirect "NoCookie.asp"
   Else
     Response.Redirect "AllowCookie.asp"
   End If %>
<HTML>
<HEAD>
  ...

All it does is check the value of the TestBrowser variable. If it's Empty we know that the browser, for one reason or another, doesn't have the ability to use a Session—which is likely to be because it can't (or won't) support our session ID cookies. If this is the case we just redirect the visitor to a page that is intended for non-session ASP users. Otherwise its business as usual, and we redirect them to the main menu of our application. Notice that it's necessary to wrap the If statement in another On Error Resume Next, in case the IsEmpty test fails. If it does, the next statement to be executed still sends them to the non-session area of the site.

Using Document Redirection

The code we've seen in the previous section is an excellent example of the way that we can redirect users to a different page at will. We can often take advantage of this method to route users through an application, depending on the current state for that user, or the application as a whole.

For example, we might allow them to chose goods they want to purchase, in a kind of virtual shopping trolley. Each time they click the Yes, I Want One button, we add the details to our Session object, using an array like we saw earlier:

Sub cmdYesIWantOne_onClick
  'Retrieve the array and current item count from the Session object ...
  LocalArray = Session("BoughtItems")
  intNumberOfItems = CInt(Session("ItemCount")) + 1
  LocalArray(intNumberOfItems) = strItemCodeNumber
  'then store the updated values back again.
  Session("BoughtItems") = LocalArray
  Session("ItemCount") = CStr(intNumberOfItems)
End Sub

When they've finished shopping, and click the All Done Now button, we only need to route them to the virtual checkout if they have actually bought anything. It's easy using document redirection:

If CInt(Session("ItemCount")) > 0 Then
  Response.Redirect "cashdesk.asp" 
Else
  Response.Redirect "thankyou.asp" 
End If

Redirecting From Within a Page

Doing a redirection like the last example is only possible from the header of a document, before any content has been sent to the browser. If we attempt it after that, we get a Buffer not empty error. Remember from Chapter 2 that if we want to provide an opportunity for redirection to occur part way through a page, we need to turn on buffering, and clear the buffer, first:

<%@ LANGUAGE="VBSCRIPT" %>
<% Response.Buffer = True %>
<HTML>
<HEAD><TITLE> Document Title </TITLE></HEAD>
<BODY>
<H1>Welcome to our site</H1><P>
<% If Session("TestCondition") = True Then
     Response.Clear
     Response.Redirect "anotherpage.asp"
   End If %>
   ...
   rest of page
   ...
</BODY>
</HTML>

© 1997 by Wrox Press. All rights reserved.