Persisting Session Information

Web sites that rely on user identification, information, and activity on more than one page typically employ session files and variables. A session is the connection between the browser and the server. Session files and variables are commonly used in Common Gateway Interface (CGI) scripts and Active Server Pages (ASP) to preserve a Web page's state and critical information, such as form data and user-specified display criteria. While information like passwords should continue to be persisted through server-side solutions with robust security, unsecure information can be persisted on the client across sessions.

Session information is usually recorded for sites that use multiple pages to accomplish a task, such as virtual shopping carts and advanced search engines. Pages that employ these variables and files can easily swell to a very large size while they juggle delivering a Web page and processing the surrounding scripts. Persistence allows most of this information to be stored on the client, thus decreasing download time and the performance hit to the server's processor(s).

The userData behavior is ideal for persisting session information on the client. For the content provider, persisting session information using userData is beneficial to performance. The capacity of the userData store is 64 KB per page, with a limit of 640 KB per domain, in a restricted security zone. See userData for information on the storage capacities in other security zones.

Note  The intention is to persist session information on the client, not to store Web pages. Because a Web page can contain damaging content, any attempt to use userData to store Web pages would be limited to the restricted security zone, so the restrictions of 64 KB per page and 640 KB per domain would be applied.

  • Essential Persistence Preparations 
    • The STYLE Block 
    • The ID and CLASS Attributes 
    • The STYLE Attribute Set Inline 
    • Methods and Functions 
  • Persisting Information Across Sessions 
  • Validating Persisted Session Information 
    • Script for the First Page 
    • Script for the Second Page 
    • Script for the Third Page 
  • Related Topics

Essential Persistence Preparations

The userData behavior requires certain elements in order to function: a style block, an ID attribute, and a CLASS attribute on the object to persist.

The STYLE Block

The style element is used to define a persistent class.

<STYLE>
   .userData {behavior:url(#default#userdata);}
</STYLE>

The ID and CLASS Attributes

The ID and CLASS attributes identify the type of persistence the element is using.

<ELEMENT CLASS="userData" ID="oPersistElement">

The STYLE Attribute Set Inline

The style can also be set inline with the element.

<ELEMENT
   CLASS="userData"
   STYLE="behavior:url(#default#userdata)"
   ID="oPersistElement"
>

The information that will be persisted with the userData behavior needs to be stored on an attribute using the getAttribute and setAttribute methods. Then, the persistent object must be saved into an arbitrary XML Store using the save and load methods. Since there potentially could be a lot of attributes to persist, a div object will be used. This is merely preference—any object that supports a persistence behavior can be used.

Methods and Functions

Functions to save and load the information need to be defined. Then, the information should be saved into a hierarchical XML Store.

<SCRIPT>
   function fnSave(){
// An attribute is written to the persistent object.
      oPersistDiv.setAttribute("sPersistValue",oPersistText.value);\
// The object is explicitly saved into an XML Store.
      oPersistDiv.save("oXMLStore");
   }
   function fnLoad(){
// The XML Store is loaded.
      oPersistDiv.load("oXMLStore");
// The information is retrieved from the persistent object.
      oPersistText.value=oPersistDiv.getAttribute("sPersistValue");
   }
</SCRIPT>
:
<BODY ID=oBody>
<DIV CLASS=userData ID=oPersistDiv ..>
</DIV>
<INPUT TYPE=text id=oPersistText>
<P>
<INPUT TYPE=button VALUE="Save" onclick="fnSave()">
<INPUT TYPE=button VALUE="Load" onclick="fnLoad()">

In the previous code snippet, the div and one of the input objects were given ID attributes of oPersistDiv and oPersistText. In the fnSave and fnLoad functions, the ID attributes are used to refer to the objects. Two input objects have been added to provide control over the functions. Event handlers may also be used to control these functions; however, the userData behavior does not expose the onsave and onload events.

Each function has two lines. In fnSave, the div object is given a new attribute called sPersistValue, and a value of oPersistText. The persistent div object is then saved into a hierarchical XML Store within the client's cache, oXMLStore.

In the fnLoad function, the persisted oPersistDiv object is loaded. The load method is called, using the name of the arbitrary XML Store name given when the save method was used. oPersistText's value is changed to the value of the oPersistColor attribute on the div object, which was set in the fnSave function.

Persisting Information Across Sessions

To persist information across sessions, each Web page that will use the persisted information needs to be prepared.

Notice that a line of script has been added that will send the browser to a new Web page when the "Save and Leave" button has been clicked. This new page will load the information set on the first page.

<HTML>
<HEAD>
<STYLE>
   .userData {behavior:url(#default#userdata);}
</STYLE;>
<SCRIPT>
   function fnSave(){
      oPersistDiv.setAttribute("sPersistValue",oPersistText.value);
      oPersistDiv.save("oXMLStore");
// After the XML Store is saved, the next page is loaded.
      location.href="userData_target.html";
   }
   function fnLoad(){
      oPersistDiv.load("oXMLStore");
      oPersistText=oPersistDiv.getAttribute("sPersistValue");
   }
</SCRIPT>
</HEAD>
<BODY>
<DIV CLASS=userData ID=oPersistDiv ..>
</DIV>
<INPUT TYPE=text id=oPersistText>
<P>
<INPUT TYPE=button VALUE="Save and Leave" onclick="fnSave()">
<INPUT TYPE=button VALUE="Load" onclick="fnLoad()">
</BODY>
</HTML>

Code example: https://samples.msdn.microsoft.com/workshop/samples/author/persistence/userData_ht1.htm

Validating Persisted Session Information

A chief concern of using session information is that a user may attempt to access a page in the middle of a required series of operations. One example would be entering the URL for a download page of a Shareware utility to bypass entering information that the utility's author requires. Another example would be entering the URL to a page that is dependent upon session variables or upon a session file that was generated on a previous page.

There are several ways of validating a page's session state before proceeding. Some common methods include using the document referrer, passing a Boolean argument, setting a cookie, or generating the page dynamically. All of these can be accomplished with the userData behavior, without sacrificing precious time or compromising security.

A means of validating the session state is to use two Boolean arguments to monitor the state of the page and the state of the persisted information. The first Boolean is local and is used for the explicit purpose of setting the persistent Boolean. In this example, the local Boolean is set to true only if the "Save and Leave" button is clicked. A script is defined for the window object's onunload event handler, where the persistent information is set and saved. Therefore, if the window is closed for any reason other than the user clicking the "Save and Leave" button, the persistent Boolean will remain false and the user will be returned to the first page that was accessed directly.

Script for the First Page

A window onunload event handler is used to set the persistent values, since the userData behavior does not expose the onsave or onload events.

<SCRIPT FOR=window EVENT="onunload">
// The window onunload event handler is used to persist information.
   oPersistDiv.setAttribute("sPersistValue",oPersistText.value);
   oPersistDiv.setAttribute("bIsValid","true");
   oPersistDiv.save("oXMLStore");
</script>
<SCRIPT>
function fnSave(){
/* When the function is called, a new location is loaded,
   thus firing the window object's onunload event.
*/
   location.href="userData_ht2_target.htm";
}
</SCRIPT>

Script for the Second Page

The onunload event handler will set the session state Boolean to false if the page was invalid for any reason.

<SCRIPT FOR=window EVENT="onunload">
   oPersistDiv.setAttribute("sPersistValue",oPersist1.innerHTML);
   oPersistDiv.setAttribute("sPersistValue2",oPersistText2.value);
// If the page is valid, then persist a boolean as true.
   if(bPageValid==true){
      oPersistDiv.setAttribute("bIsValid","true");
   }
   else oPersistDiv.setAttribute("bIsValid","false");
// Save the XML Store.
   oPersistDiv.save("oXMLStore");
</SCRIPT>
<SCRIPT>
var bPageValid=false;
function fnSave(){
   bPageValid=true;
   location.href="userData_ht2_target2.htm";
}
function fnLoad(){
   oPersistDiv.load("oXMLStore");
   if((oPersistDiv.getAttribute("sPersistValue"))
     &&(oPersistDiv.getAttribute("bIsValid"))
     &&(oPersistDiv.getAttribute("bIsValid")=="true")){
      oPersist1.innerHTML=oPersistDiv.getAttribute("sPersistValue");
      bPass=true;
   }
   else{
      bPass=false;
   }
   oPersistDiv.setAttribute("bIsValid","false");
   if(bPass==false){
/* If the persistent boolean is nonexistent or false,
   then the user is bumped back to the first page in the sequence.
*/
      var sError="You cannot access page 2 until you complete page 1.";
      alert(sError);
      location.href="userData_ht2.htm";
   }
}
</SCRIPT>

Script for the Third Page

The only purpose of the onunload event handler is to set the session state Boolean to false, so that page cannot be accessed directly.

<SCRIPT FOR=window EVENT="onunload">
   oPersistDiv.setAttribute("bIsValid","false");
   oPersistDiv.save("oXMLStore");
</SCRIPT>
<SCRIPT>
function fnLoad(){
   oPersistDiv.load("oXMLStore");
   if((oPersistDiv.getAttribute("sPersistValue2"))
     &&(oPersistDiv.getAttribute("sPersistValue"))
     &&(oPersistDiv.getAttribute("bIsValid"))
     &&(oPersistDiv.getAttribute("bIsValid")=="true")){
// If the two persistent values exist, set the boolean to true.
      oPersist1.innerHTML=oPersistDiv.getAttribute("sPersistValue");
      oPersist2.innerHTML=oPersistDiv.getAttribute("sPersistValue2");
      bPass=true;
   }
   else{
      bPass=false;
   }
   if(bPass==false){
/* If the boolean is false, move the user back
   to the first page in the sequence.
*/
      var sError="You cannot access page 3 until you complete 1 and 2.";
      alert(sError);
      location.href="userData_ht2.htm";
   }
}
</SCRIPT>

In order to continue beyond the third page, the persistent Boolean would have to be set to true as it was for the first and second pages.

Code example: https://samples.msdn.microsoft.com/workshop/samples/author/persistence/userData_ht2.htm