.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

Tuesday, 24 March 2009 16:52:13 (GMT Standard Time, UTC+00:00)
Hi, this works great. I have been searching all day looking at various examples and ways on how to implement a keep-alive but this is the best one I have found. I am using this on my web based application for Administrators be keep logged in until they log out.

Nice one!
Garry Grimshaw
Tuesday, 24 March 2009 17:02:56 (GMT Standard Time, UTC+00:00)
hi gary, glad you found it useful!
tim
Monday, 03 August 2009 13:17:11 (GMT Daylight Time, UTC+01:00)
awsome, lightweight and versatile
Brendan Saunders
Friday, 30 October 2009 20:50:59 (GMT Standard Time, UTC+00:00)
If you set-up a javascript timer to fire 30 seconds before the session timeout, wouldn't it
automatically reset the timeout period? This seems like a simpler solution.

If you want to alert the user, just popup an alert first.
Clyde
Sunday, 01 November 2009 13:21:15 (GMT Standard Time, UTC+00:00)
hi clyde. the point of this is not to automatically reset the timer, in which case you should just set a very large timeout and not require any javascript at all. in this case we want to keep a reasonably short session timeout, but prevent the user from losing unsaved information if they stay on the same page for a long time. if you re-read the article this is explained.
best
tim
tim
Tuesday, 26 April 2011 09:59:38 (GMT Daylight Time, UTC+01:00)
HI ,,
thanks for the article.. i was in lot of exploration for the same problem you mentioned above.
Actually i am using asp.net2.0 with vb, so was confused how to use above code since we need to keep in util class?
Please explain how to implement this in vb asp.net2.0

KP
kp
Monday, 02 April 2012 12:12:54 (GMT Daylight Time, UTC+01:00)
Hi,
i want implement auto save functionality in wizard control steps.i have 10 steps in my wizard control i want auto save functionality in each next step. or otherwise i fill the form in 5 steps and i want close the browser that time i want save the previous 5 steps in my database and the next time i am login the page cursor automatically goes on the 6 steps.
please help me.

This is in the asp.net using c#


Thanks in Advanced
Manoj Tambe
Thursday, 17 May 2012 06:28:47 (GMT Daylight Time, UTC+01:00)
hi KP,

This code is similar with minor changes in syntax for vb.net
Function you need to call from util will be -

Public Shared Sub KeepAlive(ByVal p As Page)
p.ClientScript.RegisterClientScriptInclude("KeepAlive", "/KeepAlive.js")
End Sub

KeepAlive.js must be on root.
The method must be public in order to call from another class/page.

Happy coding,

Pankaj
Pankaj Sathe
Monday, 06 May 2013 09:08:15 (GMT Daylight Time, UTC+01:00)
hi.
It not active in my project :
KeepAlive.js

var timerID = 0; // used to track the timer function
var interval = 1000 * 60 * 15; // 15 mins
/// <reference path="Ping.asmx" />

var KeepAliveUrl = '/Ping.asmx/GetPing'; // 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);

Ping.cs

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Services;

/// <summary>
/// Summary description for Ping
/// </summary>
[WebService(Namespace = "http://tempuri.org/")]
[WebServiceBinding(ConformsTo = WsiProfiles.BasicProfile1_1)]
// To allow this Web Service to be called from script, using ASP.NET AJAX, uncomment the following line.
// [System.Web.Script.Services.ScriptService]
public class Ping : System.Web.Services.WebService {


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


I put Until.cs in App_Code folder . Then I call it in a page not root ! Please help me ?
BinhMichel
Tuesday, 07 May 2013 10:24:42 (GMT Daylight Time, UTC+01:00)
If you're having trouble getting this to work, make sure you can browse to the web service /Ping.asmx (or whatever you call it) in your web browser, and invoke it and read the "OK" result correctly. then make sure your ASPX page is referring to the correct web service address.
Tim
OpenID
Please login with either your OpenID above, or your details below.
Name
E-mail
Home page

Comment (Some html is allowed: a@href@title, strike) where the @ means "attribute." For example, you can use <a href="" title=""> or <blockquote cite="Scott">.  

[Captcha]Enter the code shown (prevents robots):

Live Comment Preview