Sometimes you want your web page to 'stay alive'. That is, if a user is filling out a complicated form, you do not want the session to time out before they are finished. The user could get very angry and rightfully so: You might even get yelled at!
It's not simply a matter of increasing the session timeout to a very large value. If you do that, the sessions would be left active in the server memory for hours—long after the visitors have left the site. Increasing the session timeout IS a solution… but not necessarily a good solution.
The goal is that the session should stay active as long as the web page is open on the client machine… even if there are no post backs to reset the session timer. When the web page is closed, the session should time out normally.
I implemented a solution for this: The client will "ping" the server at intervals of less than the session timeout which will reset the session timer. This is known as the Heartbeat design pattern (I couldn't find a decent site/page to link to).
Miscellaneous Setup Stuff
For testing purposes, I set the Session Timeout to two minutes in web.config:
<system.web>
<sessionState timeout="2">
</sessionState>
</system.web>
To trace what is happening, I used a utility function called ODS (it's in a class called MiscUtilities
):
public static void ODS(string Msg)
{
String Out = String.Format("{0} {1}", DateTime.Now.ToString("hh:mm:ss.ff"), Msg);
System.Diagnostics.Debug.WriteLine(Out);
}
To watch the Session State events, I added debugging strings to the global.asax file:
<%@ Application Language="C#" %>
<script RunAt="server">
void Application_Start(object sender, EventArgs e)
{
MiscUtilities.ODS("****ApplicationStart");
}
void Session_Start(object sender, EventArgs e)
{
MiscUtilities.ODS("Session_Start");
}
void Session_End(object sender, EventArgs e)
{
MiscUtilities.ODS("Session_End");
}
Here are the details: We need a method at the server for the client to call. We use a WebMethod
.
- There must be a
ScriptManager
on the page. - The
ScriptManager
must have EnablePageMethods
set to true
. - The
WebMethod
must be public
and static
. - The
WebMethod
must have the EnableSession
attribute set to true
.
<asp:ScriptManager ID="ScriptManager1" runat="server"
EnablePageMethods="true">
</asp:ScriptManager>
public partial class _Default : System.Web.UI.Page
{
[WebMethod(EnableSession=true ) ]
public static void PokePage()
{
// called by client to refresh session
MiscUtilities.ODS("Server: I am poked");
}
We need JavaScript at the client to call the server function at fixed intervals:
<script type="text/javascript">
var HeartBeatTimer;
function StartHeartBeat()
{
if (HeartBeatTimer == null)
HeartBeatTimer = setInterval("HeartBeat()", 1000 * 10);
}
function HeartBeat()
{
Sys.Debug.trace("Client: Poke Server");
PageMethods.PokePage();
}
<body id="MyBody" onload="StartHeartBeat();">
Here is what the output looks like without the heartbeat:
10:22:43.03 ****ApplicationStart
10:22:45.13 Session_Start
10:25:00.00 Session_End
Here is the output with the heartbeat:
10:26:06.10 ****ApplicationStart
10:26:08.05 Session_Start
Client: Poke Server
10:26:18.93 Server: I am poked
Client: Poke Server
10:26:28.95 Server: I am poked
Client: Poke Server
10:26:38.96 Server: I am poked
Client: Poke Server
10:26:48.98 Server: I am poked
. . . (lines deleted)
Client: Poke Server
10:29:59.45 Server: I am poked
Client: Poke Server
10:30:09.47 Server: I am poked
Client: Poke Server
10:30:19.48 Server: I am poked
. . . (lines deleted)
It looks like the session is staying alive while the client is idle: Excellent!
I hope someone finds this useful.
Steve Wellens