Weird Thoughts From Eric's Head

Categories : All | AJAX | BUSINESS | PERSONAL | PROGRAMMING | BOOK REVIEW

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.
confirm image

Then click the ok button
timestamp image

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


Hello Eric can u please tell me how can i display values retrieved from database in my page. I read ur blogs and i am now trying to apply it in my current project. In this i want to display details of a product on the selected index change event of a drop down list. I retrieved the data from db but i dont know how to display it back in the current page (in some labels). I am using ASP.Net for server side coding. Plz help thanX Anz
Hi Update Users Session with Ajax is Very Good demo. when periodic Refresh is Happening using Ajax then how can we inactivate Session.
Good show! This is (minus the statusbar update) exactly what I need. Two comments, though (from the jsp example). First off, you have a typo "loose" where "lose" should be. Next one, is... can you explain how the session expiration condition is met? I'm not sure I understand what reqXML.responseText is supposed to be when there's an expired session... basically I am skeptical (without having tested it) that the expiration message will ever occur.
You might even want to consider getting rid of the alert box. Some users may not know (or want to know) what a "session" is. If the browser is still on the page, have the session automatically refresh itself.
My response to that is: why have a session then? If a person walks away from their desk, I rather have it cancel out then be open for anyone to use. The people I wrote this for know what a session is since they kept timing out and were annoyed. Why it takes 30 minutes to answer 10 questions blows my mind! LOL

Eric
Yeah, I guess it comes down to understanding your "audience". Maybe you need to set up some webcams to see why it really takes 30 minutes to answer 10 questions? :)
Make it even better: 5 of the 10 questions are radio buttons that say rate me 1-5!
I mean the code similar to what you have posted on http://radio.javaranch.com/pascarello/2005/10/25/1130246930301.html. I am looking for something similar for JSP.
change the server side reference to point to your jsp page and put the same code from the above example into the page. All the clientside is looking for is that "token" string from the server. Eric
Im assuming that there are some files missing. Where is the .aspx.vb code? Would you possibly post a .zip file will all the files? Thanks;
The vb code really does not matter on the page that is making the request. That is what I am assuming you are asking for.
Eric
ajax do not send automaticaly php session, i have had to add manualy a variable in "get" to can use session.
Eric, this works for me except that I cannot get the session expiration alert to occur (as anonymous above suspected). Thanks
I believe my above problem stemmed from the sessionUpdater.aspx page being cached, so the callback would get the same server time as it did on the first callback. I added the following directive to the sessionUpdater.aspx and it solved the problem. <%@ OutputCache Location="None" VaryByParam="None" %> Thanks
I have this error, why? No es válido en el nivel superior del documento. Error al procesar el recurso http://192.168.1.4/hiscli/sessionUpdater.aspx. Línea 1, Posición 1 Actualizada - Hora Servidor: 04/08/2005 12:48:57 p.m. ^
When are you getting this error exactly? After the request has come back? What is the code?
Hi just surfing the web to see if i can find a better way of creating a session timeout for clientside than what I have already in place.

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.
I found this trick very handy, but I do have to agree with several other posters that I don't believe the "session expired" message will ever be shown - since sessionUpdater.aspx does not make use of the session. The session WILL actually expire, though. By calling LoadXMLDoc without popping the dialog box, this makes a neat way to automatically and silently extend the session for as long as the browser window is open.
Hi, I have to support Eric by attesting to the fact that the second alert does indeed occur if the user takes no action on the confirm dialog box or clicks cancel and then the session times out. The callback will not be able to read the text contained in sessionUpdater.aspx and therefore the 'expired' alert will be displayed. Terry
Why won't the callback be able to read the text from sessionUpdater.aspx? There's nothing in it that requires the existence of a session to output the proper text. I apologize that I'm too lazy to wait 20 minutes, or to change the default ASP.NET timeout to debug it :)
Jeff, Let me clarify the context in which I am using this functionality. The pages of my site that will take advantage of it are in secured directories and require the user to be authenticated. The authentication cookie timeout is also 20 minutes. I placed the sessionUpdated.aspx page in the same secured directory as the page that does the callback. If the timeout occurs, the callback will be directed to my login page instead of sessionUpdated.aspx and the following condition will fail...... if(reqXML.responseText.indexOf("Session Updated - Server Time:") == 0...........resulting in the second alert. Terry
I like the idea of using a floating div to display the alert rather than the dialog. If they do not respond before the session expires this would allow you to replace the message with a statement that their session has indeed expired. Also a message in a div does not interupt their workflow in the same way as an alert. I hate it when I'm typing and a message pops up only to be dismissed by my typing before I get to read it! Great tip though!
I like that idea too. When I get done working on my book I will have some DHTML fun and make it float onto the page or something.

If anyone has a version to share, post a link.
Eric
This is definetely a nice tip. I'd like to raise an additional point though: suppose the user is away from the PC the moment the alert pops up. Now, also suppose they only arrive back long after the session is expired. What they will see is a box reminding them their session will expire. However, pressing OK in THIS case will not help very much in extending the session. Isn't that a bit unfortunate? Maybe it's a better idea to display a hidden DIV or something that is really standing out on the page with a form button the user can press. This gives you complete freedom as to handle an absent user. Please correct me if I'm wrong
That point has been raised a few comments ago and when I get done with my final stage in the book I am going to develop a fancier div interface which will warn the user and be able to detect that the session has expired. Using the confirm is not user friendly!
Dear Friends, i am doing lot of things with AJAX like calling webservice, filling grid using ajax etc. if u want, i can mail u my sample code. my email id is software_guy_india@yahoo.co.in
Dear Friends, i have developed a custom control to handle session expeiry using Eric' "Update User's Session with AJAX" logic. i will upload my code soon. Thanks to Eric's Session updator. Kannan S software_guy_india@yahoo.co.in Dubai, UAE
Dear Frinds, I wud like to know how secure is AJAX technique. As we have to specify the URL of our server side page along with the parameters. Anyone can understand this URL and parameters that we are passing and use the same URL in anyother application and get the data from the server. Is n't it a threat to security....
Manoj, Any form has the same issue. I can submit a form from another page and submit it to your URL. You need to perform checks on the server side to see where the request is coming from. Eric
Well done!
Hey, I just want to update a window with Ajax. How can i do that? Instead of setting a update time to for example 30sec, i just want to refresh when a new comment is posted. Is this possible?
Problem is there is no "real" way to have the server call the client. What I do is this. Make your server side code sleep. Do it a few times, checkig for data, and then send the request back. You can not keep it sleeping for too long or you will end up with problems with the request.

Doing it this way you will be your best bet in limiting the number of requests to check for new data.

Eric
New version of the script is available at: http://radio.javaranch.com/pascarello/2005/10/25/1130246930301.html
Hi, I am trying to display some input screens, so as a user clicks on the submit button a background process is initiaited and the results are shown to the user in the same page, now when i try to call the javascript function on the submit of the second form, it says that the function does not exist whereas it does exist in the html code of the results. any idea what i am doing wrong.
I am assuming that either you are embeding the form inside the other, which is a no-no. OR you have a submit buttun named submit, which is also a no no.
Hi Eric, Thanks for your reply but i am clearing out the contents of the div before placing the new contents into the same div, dosent this mean that the old data has been removed, if no how can i do that. Also the button is named btnNext and even if i name it something else, i get a error object not found, i have faced this problem only with htm pages having a form and javascript content, i could keep the javascript static but unfortunately most of the content is dynamic, like for that one which validates the form, which is created dynamically from the database along with the form contents. Thanks in advance
This is really an incomplete solution of the heartbeat / timeout problem. IF someone was to close the browser this solution wouldn't be able to notify the server so the server would have an open session state. A more complete solution would be have a server heartbeat and timeout working in tandam. That way if a server doesn't receive a response from the client periodically it can close the session at the server end.
Eric you are awesome man.....
I always thank those who provide useful code. Thanks. I had an epiphany, I thought wouldn't it be cool to use this new technology to be able to warn users about their session. Hmf, I'm only about a year behind.
Hey friends, i m developing chatting web application in C#. and for that i have created a general chat window for all session using AJAX. And i can store and retrieve data back. and also i can display it on the screen, but i cannot display it on all session user screen means it should be display to all user cos it is general chat window. so please can anyone give me solution?
Hi Eric, Is it possible for you to post the code that works with JSP's Thanks
Did you miss the button that shows the jsp version of the code? Eric
Does anyone know what the codes are exactly in the sessionUpdater.jsp?
Eric how will your session management code work for a shopping basket scnerio where normally basket content is stored in sessions?

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>

Hi,

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

Hello Eric. Great code for a newbie to AJAX like me. It quite comprehensive but i'm stuck. I never get the session expiration alert - "Your session appears to have expired. You may loose your current data." - I left the page idle for hours and I only get the confirm box which prompts me to Ok or Cancel to renew the session and what I need is that alert informing that the session is expired. Any ideas? Thanx in advance Leo
what response is retrived from xml doc bcoz it shows error as There was a problem retrieving the XML data SessionUpdater.jsp which is this file? how to solve this?
i faced one problem with above solution When the first time timer starts it works fine by giving message. But suppose session timeout period is 20 min and alert is given 5 min before i,e is on 15th min. In between that if i hit any action (eg save or list)the timer is not resetting to its original value that is 20 min it is continuing from 15th min and after 5 min page is getting expired which should not happen. Plz tell me thhe solution?????
Prashant, There is no XML involved and what do you mean by the timer is not resetting. You talking about the server or on the client?
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
I used this code in my app but the code: if (reqXML.responseText.indexOf("Session Updated - Server Time:") == 0) for some reason is never true. So my session appears always to be expired. alert(reqXML.responseText) has this string "Session Updated - Server Time:" in it. Please let me know where I am going wrong.
Well you probably have something else in the response. In that do the check via:
if (reqXML.responseText.indexOf("Session Updated - Server Time:") != -1)
Eric
I tried that too (!= -1) but now the session the if condition is always true.
Well if your session expires, than that line of code should not be there, the page your are requesting from the server should be redirected to the log in page. Eric
You just need to have a php to reference something like:
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
Hi Eric, You have a nice code. Can you help me find a solution to my problem using AJAX. See, initially I have a login form called Login.aspx and when the user successfully logged the user will be redirected to Default.aspx, which has a logout link in it and contains crucial information. Now when the user click the logout link the user will be redirected to the login form; however, when I click the browser's back button the information is still there. I would like to know how this will be resolved. Is there a way I can use this code for this concern? Please advise. Thanks, Doms


Add a comment

Title
Body
HTML : b, i, blockquote, br, p, pre, a href="", ul, ol, li
Math Quiz 7 + 7 = (Helps stop blog spam)
Name
E-mail address
Website
Remember me Yes  No 

E-mail addresses are not publicly displayed, so please only leave your e-mail address if you would like to be notified when new comments are added to this blog entry (you can opt-out later).

TrackBack to http://radio.javaranch.com/pascarello/addTrackBack.action?entry=1120592884938