code download
Sessions are a way of preserving information on a web site between page hits, allowing the programmer to emulate a stateful application when, in fact, web pages are not really stateful. They are also one of the banes of web development, since sessions eventually timeout when there is no interaction between the user and the web app for a prolonged period of time. In ASP.NET, this period has a default of 20 minutes, which is really hardly enough time to pick up a donut, refill one’s coffee, and chat with fellow workers before returning to one’s computer. What this often means is that the user, upon returning to their computer and continuing work after a 20 minute break will find that all of the data entry they have been doing has been lost. Worse, strange errors will begin to appear in his web browser if the loss of a session is not handled gracefully.
The most common workaround is to increase the session grace period, called the session timeout. This is set in your web.config file, and typically looks like this (the timeout period is measured in minutes):
<system.web>
<sessionState
mode="InProc"
cookieless="false"
timeout="20"
/>
</system.web>
A second way of handling this is to add extra code to an app that keeps the session state alive even if the user isn’t doing anything.
A third, and the most common, way is to provide code that redirects a user to a “session expired” page if they try to interact with a web page for which the session has timed-out. This can be a bit awkward, however, since it is a passive solution that can cause the user some dismay as they hit a submit key only to be taken to a completely unexpected page.
This post deals with an active approach to the same problem. When the user’s session has expired, it will generate a popup message in the user’s browser window letting him know that he has been inactive for too long. Additionally it can redirect the browser to a new page with a warning message letting him know what happened. The user still loses all of his work, of course, but at least this way he knows what happened when he returns to his desk following his coffee break.
This solution uses three tricks. One is the event model for Master Pages in ASP.NET: whenever a Content Page is refreshed, its OnLoad event is called, along with the OnLoad events of the Master Page and any user controls hosted by either the Content Page or the Master Page (the actual order of these events is 1. controls on the Master Page, 2. controls in the Content Page, 3. the Master Page and finally 4. the Content Page).
The second trick is the way ASP.NET Extensions Timer control gets reset. This is done simply by setting the interval to a new value. Every time the interval is set to a new value, or even the same value, the countdown on the timer begins again.
The third trick is that the session timeout one sets in the web.config file can be read programmatically simply by querying a property of the Session object.
Putting all of this together, one can build a web user control that simply sits on a Master Page and knows when the user session is ready to expire. It resets itself to the full timeout period any time a Content Page is refreshed. when the session expires, the user control can raise an informative message, redirect to another page, or, potentially, simply extend the session timeout (not covered here, but easy to do if you are interested).
A user control to monitor the session timeout is included in the code sample linked at the top of this post. Here is how you can build your own.
Session Timeout Monitor Recipe:
Ingredients:
- One Master Page
- One User Control
- An Update Panel
- An ASP.NET Ajax Extensions Timer
- A Panel control
- A Button control
1. Create a new User Control in your project.
2. Drop an Update Panel on the User Control and set its mode property to “Always”.
3. Add an Extensions Timer (not to be confused with the Futures TimerControl) to your project, dropping it in the Update Panel. Name it TimerTimeout.
Normally, this configuration of the timer control and a conditional update panel is used to refresh a portion of a web page on a regular schedule, for instance in order to create a self-updating clock display. In this case, however, the timer and update panel are used simply to trigger a notification that the session has expired.
4. In the User Control’s code behind, add the following lines to the OnLoad event:
protected void Page_Load(object sender, EventArgs e)
{
int milliseconds = 60000;
TimerTimeout.Interval = Session.Timeout * milliseconds;
}
This event will be called any time a content page is refreshed. Whenever this happens, the code inside the event handler resets the AJAX Extensions Timer control to the full session lifespan as set in the web config file, in effect making the timeout for the Timer match the timeout for the session.
Since the Timer control’s Interval property is measured in milliseconds, while the session.Timeout is measured in minutes, a conversion factor of sixty thousand must be used to translate one time period into the other.
To finish this notifier, the Timer’s Tick event needs to be handled. The Tick event gets called when the Timer’s Interval finally runs out. In this implementation, the Tick event can either generate a popup message or cause a page redirect.
5. Place a Panel inside the Update Panel. Set its Visible property to false.
6. Write a simple message inside the Update Panel, such as “Your session has expired.”
7. Drop a Button inside the Panel. This Button will be used to allow the user to hide the popup message.
8. Add a public property to the User Control called SessionExpiredRedirect:
private string _sessionExpiredRedirect;
public string SessionExpiredRedirect
{
get { return _sessionExpiredRedirect; }
set { _sessionExpiredRedirect = value; }
}
This will be used to set the web page to which the Timer will redirect the user upon session timeout. If no value is set, a popup message will appear, instead.
9. Handle the Timer’s Tick event:
protected void TimerTimout_Tick(object sender, EventArgs e)
{
if (!string.IsNullOrEmpty(SessionExpiredRedirect))
{
if (SessionExpiredRedirect.IndexOf("~")==0)
Response.Redirect(
VirtualPathUtility.ToAppRelative(
SessionExpiredRedirect));
else
Response.Redirect(SessionExpiredRedirect);
}
else
this.PanelTimeout.Visible = true;
}
This handler checks to see if a value has been set for the SessionExpiredRedirect property. If not, it makes the Panel control inside the Update Panel visible.
10. To make the Panel control truly popup, set its CssClass property to “timeoutMessage”. Add the following css style to the page.
<style type="text/css">
.timoutMessage
{
position:absolute;
top:100px;
left:200px;
background-color:#F5F7F8;
border-style:groove;
border-color:Navy;
padding:15px;
}
</style>
11. Finally, compile this User Control and drag it on to the Master Page. In design mode, the user control will display a misleading exception message. Just ignore it.
12. Make sure the Master Page includes an ASP.NET AJAX Script Manager component.
This completes the recipe. Any Content Page in this project will now automatically include the timeout monitor you have built. Cookies are optional: this recipe will work with a session managed either with cookies or in cookieless mode. It will only work if the session mode is InProc.
Garnish with buttered radishes. Serve at room temperature.
(Code snippets formatted using manoli.net.)