.Net ramblings
# Thursday, 19 February 2009
A simple Auto-Save / Keep Alive feature for Asp.Net
today i came across a situation where a user was spending a long time filling out a form.  they went past the session timeout and when they hit save they got booted back to the login screen, having lost the previous 30 minutes of work.  i looked around the net and found a few options with AJAX and what not but it doesn't make sense to keep renewing the session automatically otherwise you might as well not have a timeout, which is there for security reasons anyway.  in my case i don't actually want to save the information to the database (it's a transaction) until the user hits the Save button, i just want to keep the session alive. 

so i came up with this idea to ask the user if they want to keep their session alive with a javascript prompt every 15 minutes. if they leave their computer and don't answer the prompt, the session will time out since they won't have interacted with the web site (regardless of how they answer the prompt after the timeout).  if they answer OK to the prompt it invokes a Ping() type web service to keep the session alive.  this is the most lightweight way i could think of doing it.  i don't want to post back to the page because that will interrupt the user and make them wait for the page to reload.

there are 3 parts:

"KeepAlive" function

I put this function in a 'Util' class so pages can easily turn on the 'Keep Alive' functionality, simply call Util.KeepAlive(this);

public static void KeepAlive(Page p)
{
p.ClientScript.RegisterClientScriptInclude("KeepAlive", "/KeepAlive.js");
}

Ping.asmx (add the web service to your root folder)

[WebMethod]
public void Ping()
{
HttpContext.Current.Response.Write("OK");
HttpContext.Current.Response.End(); // this makes the result easier to parse than an XML web service message
}

KeepAlive.js (put this file in your root folder)

var timerID = 0;	     // used to track the timer function
var interval = 1000*60*15; // 15 mins
var KeepAliveUrl = '/Ping.asmx/Ping'; // replace your web service address here
var xmlhttpKeepAlive;

function AutoSaveSubmit()
{
if(confirm('15 minutes of idle time has passed, do you want to keep your session active?'))
InvokeWebService();
}

function InvokeWebService()
{
if (window.XMLHttpRequest)
{
xmlhttpKeepAlive=new XMLHttpRequest();
xmlhttpKeepAlive.onreadystatechange = xmlhttpChangeKeepAlive;
xmlhttpKeepAlive.open('GET',KeepAliveUrl + '?T=' + timerID,true);
xmlhttpKeepAlive.send(null);
}
// code for IE
else if (window.ActiveXObject)
{
xmlhttpKeepAlive=new ActiveXObject('Microsoft.XMLHTTP')
if (xmlhttp)
{
xmlhttpKeepAlive.onreadystatechange = xmlhttpChangeKeepAlive;
xmlhttpKeepAlive.open('GET', KeepAliveUrl + '?T=' + timerID, true);
xmlhttpKeepAlive.send();
}
}
return false;
}

function xmlhttpChangeKeepAlive()
{
var text;
if (xmlhttpKeepAlive.readyState == 4)
{
text = xmlhttpKeepAlive.responseText;
if (xmlhttpKeepAlive.status==200) // OK
{
if(text == 'OK') // reset the timer
timerID = setTimeout('AutoSaveSubmit()', interval);
else
alert('Your session has already expired.\nIf you have any information on this page you will lose it if you try to save this page now. You have 2 options to avoid losing the information on this screen.\n\nOption 1: open a new internet window and log in again to the web site, then close that window and go back to this window, at which point you will have a new session and you will be able to save the information.\n\nOption 2: Copy all the text you have typed on this page and paste it into another program (such as Word or Notepad), then log in to the web site again (click the home page) and come back to this page, and paste in the text again.\n\nTo prevent this happening in the future, click OK on the 15 minute reminder box each time it appears, this will keep your session active. If you do not answer the reminder within 10 minutes the session may expire.');
}
else
alert('Error: ' + xmlhttpKeepAlive.status + '. The session may have already expired, please try to save the page now');
}
}
window.setTimeout('AutoSaveSubmit()',interval);

You might be wondering why i append the timer code/number to the url of the web service.  The reason is because IE has a caching bug and will not actually send the XmlHttp request unless the URL is different to what it has in its history, it will just return the previous result.


Thursday, 19 February 2009 16:18:50 (GMT Standard Time, UTC+00:00)  #    Comments [10]  Asp.Net