Steve Wellens

Programming in the .Net environment

Sponsors

Links

AH, Ah, ah, ah…Staying Alive…Staying Alive

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>

 

To trace what is happening, I used a utility function called ODS (it's in a class called MiscUtilities): 
/// ---- ODS ---------------------------------------
/// <summary>
/// Output Debug String with time stamp.
/// </summary>
 
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.

  1. There must be a ScriptManager on the page.
  2. The ScriptManager must have EnablePageMethods set to true.
  3. The WebMethod must be public and static.
  4. 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()
    {
        // pulse every 10 seconds
        if (HeartBeatTimer == null)
            HeartBeatTimer = setInterval("HeartBeat()", 1000 * 10);
    }
 
    function HeartBeat()
    {
        // note: ScriptManger must have: EnablePageMethods="true"
        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

Comments

Koolraaga said:

Pretty Neat.. Thank You

# June 9, 2009 7:09 PM

Nemesis116 said:

A+ :)

# June 10, 2009 8:05 AM

rajbk said:

I would personally increase the session timeout value. If you really wanted to use a timer approach, I would do something like this instead:

   <asp:ScriptManager ID="ScriptManager1" runat="server">

   </asp:ScriptManager>

   <asp:UpdatePanel ID="UpdatePanel1" runat="server">

       <ContentTemplate>

           <asp:Timer ID="Timer1" runat="server" Interval="1000">

           </asp:Timer>

       </ContentTemplate>

   </asp:UpdatePanel>

# June 12, 2009 2:35 PM

SGWellens said:

The disadvantage to using the UpdatePanel method is that it invokes the Page_Load event (and other page processing events as well).

This could be a huge problem depending on what you are doing in the page events.

# June 12, 2009 5:37 PM

Elbaz said:

it sounds very good solution.

# June 26, 2009 11:54 AM

raghav_khunger said:

Hi,Steve

That is great!.Helpful

# July 4, 2009 2:57 PM

Ed said:

Found that useful. Thanks.

# August 6, 2009 2:40 PM

Anuj Tripathi said:

That is excellent !!!

# March 8, 2010 7:28 AM

abu hamzah said:

Looks promising... is there a way to convert jquery and ajax?

# April 20, 2010 10:18 PM

SGWellens said:

"Looks promising... is there a way to convert jquery and ajax?"

I see no advantage in making it dependent on an outside library.

Note: And I like jQuery.

# April 20, 2010 11:21 PM

SGWellens said:

"This is not a scalable solution, imagine many users are hitting the server just to keep their session alive!!!"

First, if the server can't handle 1 ping every 19 minutes, you are already in trouble.

The jQuery solution is nice but does have some drawbacks:  

If the user clicks the nag screen each time it appears, you are manually pinging the server which is the exact same problem as your initial complaint.

If the user is getting coffee when the nag screen appears, the session and the user's work. will be lost.

Some people don't like nag screens.  And they have a tendency to popup at inopportune times.

Still, it's a nice control and I can see people using it.

# September 20, 2010 9:44 PM

saxxxon said:

seems nice to me. we can update it via noting the load on server. if it is overloaded then timer can be set to some bigger value ....

# October 1, 2010 3:49 AM

Kaban said:

Hey man, nice post!

i have a question though!

what is MiscUtilities

and how can I add it to the code?

Thanks

# March 4, 2011 12:28 PM

SGWellens said:

>> what is MiscUtilities

It's just a static class I use to hold several static utility functions.  You could create your own (with any name).

# March 4, 2011 12:41 PM

Shannon said:

Thanks for the post!  One question though...

What's the best way to implement this using master pages?  I've read that in the page load event of the content pages, I need to wire up the onLoad of the master page but upon doing so I still get PageMethods is not defined errors.

# May 4, 2012 2:54 PM

SGWellens said:

You should post questions on the http://forums.asp.net/ web site or  http://stackoverflow.com

# May 4, 2012 5:29 PM