Update User's Session with AJAX
[edit]Make sure to look at the new version of the script here: Round 2 version[/edit]
Well I am a little behind on my blogging here! Well I said I was going to do another AJAX example so here we go.
On some applications I help to develop, users were complaining that they were getting timed out of the application. I have no idea what they were doing on a single page for 30 minutes, but they complained. I guess they should not take that phone call!
Anyway we needed a solution to notify the user they were about to be timed out without posting back the page. Well since I am writing Ajax in Action, I proposed an Ajax solution. The Ajax solution keeps us from posting back the page to the server or opening up a pop up windw. Both methods have there flaws since the post back method can loose data if we happended to mis a viewstate field and the pop up window may be blocked by a pop up blocker. You can never be sure that the pop up would get through.
So I came up with a little script that uses AJAX to call a server side page. The server side, when called, updates our session. So the code for the server is only a few lines.
Select your language so you see the right code!
VB.NET code
Now with a .net page, we need to remove all but the code behind reference from our aspx page. In this case I called the page sessionUpdater.aspx.
<%@ Page Language="vb" AutoEventWireup="false"
Codebehind="sessionUpdater.aspx.vb" Inherits="TestAJAX.sessionUpdater"%>
The code behind then just sets the content type of the page and then outputs a string with the time stamp within the Page_Load.
Private Sub Page_Load(ByVal sender As System.Object, _
ByVal e As System.EventArgs) Handles MyBase.Load
Response.ContentType = "text/xml"
Response.Write("Session Updated - Server Time: " & DateTime.Now.ToString)
End Sub
Then we have the Client Side code.
To make this easy we can use an external JavaScript file so we need to link to it in our page.
<%@ Page Language="vb" AutoEventWireup="false" Codebehind="sessionTimeout.aspx.vb" Inherits="TestAJAX.sessionTimeout"%>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
<html>
<head>
<title>sessionTimeout</title>
<script type="text/javascript" src="SessionWarningTimer.js"></script>
</head>
<body>
<form id="Form1" method="post" runat="server">
<</form>
</body>
</html>
Then we have our external JavaScript file (SessionWarningTimer.js):
var reqXML;
function LoadXMLDoc(url){
if (window.XMLHttpRequest){ //Mozilla, Firefox, Opera 8.01, Safari
reqXML = new XMLHttpRequest();
reqXML.onreadystatechange = BuildXMLResults;
reqXML.open("GET", url, true);
reqXML.send(null);
}
else if(window.ActiveXObject){ //IE
reqXML = new ActiveXObject("Microsoft.XMLHTTP");
if (reqXML) {
reqXML.onreadystatechange = BuildXMLResults;
reqXML.open("GET", url, true);
reqXML.send();
}
}
else{ //Older Browsers
alert("Your Browser does not support Ajax!");
}
}
function BuildXMLResults(){
if(reqXML.readyState == 4){ //completed state
if(reqXML.status == 200){ //We got a sucess page back
//Check to verify the message from the server
if(reqXML.responseText.indexOf("Session Updated - Server Time:") == 0){
window.status = reqXML.responseText; //display the message in the status bar
SetTimer(); //restart timer
}
else{
//display that that session expired
alert("Your session appears to have expired. You may loose your current data.");
}
}
else{
//display server code not be accessed
alert("There was a problem retrieving the XML data:\n" + reqXML.statusText);
}
}
}
function ConfirmUpdate(){
//Ask them to extend
if(confirm("Your session is about to expire. Press 'OK' to renew your session.")){
//load server side page if ok
LoadXMLDoc('sessionUpdater.aspx');
}
}
var timerObj;
function SetTimer(){
//How long before timeout (should be a few minutes before your server's timeout
var dblMinutes = .2;
//set timer to call function to confirm update
timerObj = setTimeout("ConfirmUpdate()",1000*60*dblMinutes);
}
//start the timer
SetTimer();
JSP code
We need to set the content type and return a string with a timestamp back to the client.
<%@ page contentType="text/xml"%>
Session Updated - Server Time: <%= new java.util.Date() %>
Then we have the Client Side code.
To make this easy we can use an external JavaScript file so we need to link to it in our page.
<html>
<head>
<title>sessionTimeout</title>
<script type="text/javascript" src="SessionWarningTimer.js"></script>
</head>
<body>
<form id="Form1" method="post">
</form>
</body>
</html>
Then we have our external JavaScript file (SessionWarningTimer.js):
var reqXML;
function LoadXMLDoc(url){
if (window.XMLHttpRequest){ //Mozilla, Firefox, Opera 8.01, Safari
reqXML = new XMLHttpRequest();
reqXML.onreadystatechange = BuildXMLResults;
reqXML.open("GET", url, true);
reqXML.send(null);
}
else if(window.ActiveXObject){ //IE
reqXML = new ActiveXObject("Microsoft.XMLHTTP");
if (reqXML) {
reqXML.onreadystatechange = BuildXMLResults;
reqXML.open("GET", url, true);
reqXML.send();
}
}
else{ //Older Browsers
alert("Your Browser does not support Ajax!");
}
}
function BuildXMLResults(){
if(reqXML.readyState == 4){ //completed state
if(reqXML.status == 200){ //We got a sucess page back
//Check to verify the message from the server
if(reqXML.responseText.indexOf("Session Updated - Server Time:") == 0){
window.status = reqXML.responseText; //display the message in the status bar
SetTimer(); //restart timer
}
else{
//display that that session expired
alert("Your session appears to have expired. You may loose your current data.");
}
}
else{
//display server code not be accessed
alert("There was a problem retrieving the XML data:\n" + reqXML.statusText);
}
}
}
function ConfirmUpdate(){
//Ask them to extend
if(confirm("Your session is about to expire. Press 'OK' to renew your session.")){
//load server side page if ok
LoadXMLDoc('sessionUpdater.jsp');
}
}
var timerObj;
function SetTimer(){
//How long before timeout (should be a few minutes before your server's timeout
var dblMinutes = .2;
//set timer to call function to confirm update
timerObj = setTimeout("ConfirmUpdate()",1000*60*dblMinutes);
}
//start the timer
SetTimer();
Save it, then we can test this out.
Open up the page and wait until you get the warning.
Then click the ok button
You can see that in the status bar, we have the time form our server showing we got the data from the server. Hopefully this shows you how easy it was to send a response to the server, retrieve its value, and display it on the screen.
Eric Pascarello
Moderator of HTML/JavaScript at www.JavaRanch.com
Author of: JavaScript: Your Visual Blueprint for Dynamic Web Pages
Co-Author of: Ajax in Action
Eric
Eric
Mine is somewhat similar but uses a layer to display the message with a count down timer and window.focus() to make the window errm well come into focus. I also use a hidden iframe to post to the server as it is more widely supported and less code.
Heres the js:
var timer
function startme(){
counts= <%Session.Timeout%> * 60
if(timer){window.clearInterval(timer)}
timer = setInterval("CountDown()",1000)
}
function CountDown(){
counts--;
if(counts<121){
document.getElementById("countDown").innerHTML=counts
//display the session timeout layer
document.getElementById("sessionTimeout").style.display='block';
window.focus()
if(counts < 1)window.location.replace('logoff.aspx')
}
}
Here is the link inside the layer:
<a href=javascript:document.HF.location.replace('blank.aspx');startme();document.getElementById("sessionTimeout").style.display='none';
>Stay logged on</a>
if anyone can think of a way to make this work better please do let me know.
If anyone has a version to share, post a link.
Eric
Doing it this way you will be your best bet in limiting the number of requests to check for new data.
Eric
Adnan,
I am not sure what you are asking exactly. All this code is doing is making sure that the user's session does not expire if it does, than they will loose their shoping cart. If the user is logged in you always can keep their cart in memory on the server with a db. If they are not, you probably need to use cookies to not loose their data.
The best thing would be to use an Ajax shopping cart, but that is a different topic alltogether!
Eric>
I keep getting the following error:
The XML page cannot be displayed Cannot view XML input using style sheet. Please correct the error and then click the Refresh button, or try again later.
--------------------------------------------------------------------------------
Invalid at the top level of the document. Error processing resource 'http://localhost:2026/WebSite2/SessionUpdater.aspx'. ...
Session Updated - Server Time: 19/06/2006 12:20:00
The error talks about using a stylesheet in the aspx.vb file but I don't have any in this test application. The js file works (tested it without the aspx codebehind). What have I done wrong?
Cheers
G
If the timer, are you not posting the page back. If you are say using Ajax to do the save, than you need to manually restart the timer by calling the code. Eric
if (reqXML.responseText.indexOf("Session Updated - Server Time:") != -1)
Eric
Session Updated - Server Time: <?php echo date("Y/m/d"); ?>
and change the timer code to reference the php page where you put this on it.
Eric