skip to content
Linkedin Twitter feed logo
11 February 2008

Session Keep-Alive Web Control

Visual Studio project structure overview

Session expiration in ASP.NET is a nasty problem. Imagine yourself filling a long form, hitting submit then boom you get the login page! That happened to me before and probably happened to you.

This problem doesn’t have an out-of-box solution in ASP.NET and there are different appraoches to solve it.

  1. Increasing the session time out. Probably you are aware of the cons of this problem which are mainly consuming more server resources.
  2. Having an image or an iframe that refreshes regularly and requests the server. This approach is a per page approach and you can select the pages to implement it on.

Personally, I’ve been using the second approach for a long time and didn’t have any problem with it. However, I made it more reusable, not to mention “cleaner”, by making it a web control.

If you are just interested in using the control then you can skip to the last section “Using the Control.”

Architecture

The architecture here is simple and consists of both server-side and client-side solutions.

Server-Side

An ASHX handler file hosted on the root of the site which when requested will renew the session and return a 1-pixel image. In my control, I called the ASXH file as session-keep-alive.ashx and this is the code:

<%@WebHandler Language="C#" Class="session_keep_alive"%>
using System.Web;
using System.Web.SessionState;

public class session_keep_alive : 
  IHttpHandler, IRequiresSessionState 
{
  private static byte[] gif = 
    {
      0x47,0x49,0x46,0x38,0x39,0x61,0x01,0x00,0x01,0x00,0x91,
      0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
      0x00,0x00,0x00,0x21,0xf9,0x04,0x09,0x00,0x00,0x00,0x00,
      0x2c,0x00,0x00,0x00,0x00,0x01,0x00,0x01,0x00,0x00,0x08,
      0x04,0x00,0x01,0x04,0x04,0x00,0x3b,0x00
    };

  public void ProcessRequest (HttpContext context)
  {
    context.Response.ContentType = "image/gif";
    context.Response.Cache.SetCacheability(
                                HttpCacheability.NoCache);
    context.Response.BinaryWrite(gif);
    context.Response.End();
  }

  public bool IsReusable {
    get 
    {
      return true;
    }
  }

}

Client-Side

On the client, my web control will render a 1-pixel image and some JavaScript code that will refresh the image every set amount of time from the ASXH file on the server. This is the control’s code:

using System;
using System.Web.UI;
using System.Web.UI.HtmlControls;
using System.ComponentModel;

namespace AT.Web.UI.Controls 
{

/// <summary>
/// Web control to keep the session alive by refreshing 
/// every set amount of time
/// </summary>
[AspNetHostingPermission(SecurityAction.InheritanceDemand, 
    Level = AspNetHostingPermissionLevel.Minimal)]
[AspNetHostingPermission(SecurityAction.LinkDemand, 
    Level = AspNetHostingPermissionLevel.Minimal)]
[ToolboxData("<{0}:SessionKeepAlive runat=server />")]
public class SessionKeepAlive : WebControl {

/// <summary>
/// Set, in minutes, the duration to trigger the session.
/// The default value is one minute
/// </summary>
[Category("Behavior")]
[DefaultValue(1)]
public int Duration {
  get 
  {
    return (int)(ViewState["Duration"] ??  1);
  }
  set 
  {
    ViewState["Duration"] = value;
  }
}

/// <summary>
/// The path of the image's URL that will be requested from the 
/// server, the default is ~/session-keep-alive.ashx
/// </summary>
[Category("Behavior")]
[DefaultValue("~/session-keep-alive.ashx")]
public string PageUrl 
{
  get 
  {
    return (string)(ViewState["PageUrl"] ?? "~/session-keep-alive.ashx");
  }
  set 
  {
    ViewState["PageUrl"] = value;
  }
}

/// <summary>
/// Applies in-line CSS style to hide the generated image. 
/// The default is true. Alternatively, you can set this to false 
/// and hide the image using your own CSS to keep your page 
/// XHTML Strict compatible.
/// </summary>
[Category("Behavior")]
[DefaultValue(true)]
public bool AutoHide
{
  get 
  {
    return (bool)(ViewState["AutoHide"] ?? true);
  }
  set 
  {
    ViewState["AutoHide"] = value;
  }
}

protected override void OnPreRender(EventArgs e) {
  base.OnPreRender(e);

  if (AutoHide) 
  {
    this.Style.Add(HtmlTextWriterStyle.Display, "none");
  }

  Page.ClientScript.RegisterClientScriptResource(
    typeof(SessionKeepAlive),
    "AT.Web.UI.Controls.JavaScript.js");

  Page.ClientScript.RegisterStartupScript(
    typeof(SessionKeepAlive), "SessionKeepAlive",

  string.Format(
    @"window.setInterval('SessionKeepAlive(\'{0}\', \'{1}\');', {2});",
    ClientID, ResolveClientUrl(PageUrl), Duration * 60000), true);
}

protected override void Render(HtmlTextWriter writer) 
{
  writer.AddAttribute(
    HtmlTextWriterAttribute.Src, ResolveClientUrl(PageUrl));
    writer.AddAttribute(HtmlTextWriterAttribute.Alt, " ");
    base.RenderBeginTag(writer);
    base.RenderEndTag(writer);
}

}
}

And here is the used JavaScript, note that I am setting the Src of the image to
the same location (the ASHX file), but changing the query string to prevent the
browser from caching the request.

function SessionKeepAlive(imageID, pageUrl) 
{
  var imageObj = document.getElementById(imageID);
  if (imageObj == null || imageObj == undefined) 
  {
    return;
  }
  imageObj.src = pageUrl + "?par=" + 
          escape((new Date()).toString());
}

Using the JavaScript as an embedded resource

I have made the JavaScript file an embedded resource to make it easier for deployment. To do that I had to do the following:

  1. Added a javascript file to the project library and called it JavaScript.js
  2. I made this file an embedded resource by selecting it and setting Build Action to Embedded Resource
  3. I have added the following line to the AssemblyInfo.cs : [assembly: WebResource("AT.Web.UI.Controls.JavaScript.js","application/x-javascript")]

Using the Control

  1. Copy session-keep-alive.ashx to your website.
  2. Reference AT.Web.UI.Controls.dll in your website.
  3. You can add this control to the VS.NET toolbox and drop anywhere on the page OR you could add it manually by adding <%@ Register TagPrefix="at" Namespace="AT.Web.UI.Controls" Assembly="AT.Web.UI.Controls" %> to the top of the page and adding anywhere in the html body. You might need to set the refresh Duration, AutoHide or PageUrl

Check the sample file for more information.

Credits

The initial code that I used two years ago was based on an article, Make session last forever, written by Gevorg on Code Project.

Licence

This software is disributed under Ms-PL. Which simply means, you can freely use it and distribute it but you must retain all copyright, patent, trademark, and attribution notices that are present in the software.

Finally, if you like the article and find the control useful, then please Kick It (using the button below) and it would be kind of you to leave a comment. All suggestions and bug reports are welcome.

Download SessionKeepAlive.zip (19.55 kb)

14Comments
leave your own
  • Rick February 24th, 2008

    Adam, when I try and add the Control from the Toolbox I get

    invalid formatetc structure

  • Adam Tibi February 26th, 2008

    Rick,

    The problem is solved, please try downloading the code again and let me know if it worked for you.

    Regards
    Adam

  • Thomas Hansen August 31st, 2008

    I did a session keep alive thing in Ra-Ajax using an Ajax Timer to poll the server every n’th minute while building a wiki system which is pretty easy. You just drag the Ra-Ajax Timer control onto the page, set its Milliseconds property to some fairly large value, and poff! It works :)

  • Adam Tibi September 1st, 2008

    Yes, but that will require a whole AJAX framework, what you have called Ra-Aajx, before even thinking of implementing this.

    This is an easy solution which can fit in any ASP.NET 2.0 and above enviroment without additional requirments.

  • Rodger Cespedes October 22nd, 2008

    Thanks Adam Tibi, I really appreciate this work you have done and for sharing, it helped me a lot :)

  • Amy November 13th, 2008

    Nice work! But I can’t make it work when dropping my usercontrol( that has your control on it) to a Master Page. Any suggestion for that?

  • Rob January 30th, 2009

    Hi Adam, I have tried to place the control on a masterpage, the page, in the update panel, outside of it and the session is lost after about 5 minutes. The handler is in the root (the vb version)/ In the web.config I have the timeout set for 5 minutes and slidingExpiration set to True. The application times out. Any suggestions?

    Thanks,

    Rob

  • Peter March 2nd, 2009

    Adam,

    Thanks for the control! Works as advertised :)

    Cheers,
    Peter

  • Hai Nam June 21st, 2013

    Hi

    It works. But when I add any more reference DLL then the Session times out.

    How can I keep the dll open from the beginning of the session to the end?

  • Adam Tibi June 21st, 2013

    @Hai Nam I am not sure I am getting your question. Could you elaborate more?

  • Hai Nam June 21st, 2013

    Oh, sorry Adam.
    My question is as follows :

    Your code works fine in my web app. Session is alive. But after I add some more DLL files as : ajaxcontroltoolkit.dll, System.Web.Extensions.dll … then Session expires in about 10 minutes.

    Can you help me with this problem ? Thanks.

  • Adam Tibi June 21st, 2013

    You might want to install a plugin for Firefox that shows JavaScript errors, you migh have a JS error.

  • Motivational Quotes August 22nd, 2014

    Currently it appears like WordPress is the top blogging platform out there right now.
    (from what I’ve read) Is that what you are using on your blog?

  • vit quay van dinh September 7th, 2014

    You should take part in a contest for one of the best sites on the net.
    I am going to recommend this site!

Leave a Reply

Gravatar