The Quandary
One of those “gotchas” that a new developer faces when working with ASP.Net is that the SessionTimeout variable you find in the web.config only applies to the server side end of things, not the client. The problem with this is that if the client’s session has ended, they won’t know it, and the next time they post back to the server, they’ll either run into an error, or have their forms blanked out (if they were working on them) and not know why.
The trick is to develop a solution that will track the timeout value on the client end (browser) as well as make the appropriate updates to the server end. Fortunately, anytime that a post back is made to the server, or a new page is loaded, ASP.Net automatically handles our session processing. Our main focus will be on developing the client end.
In order to prevent the user from accidentally clicking elsewhere and bypassing the warning, we’ll present the warning as a modal popup window that they’ll be forced to interact with. As the title says, I’ll show you how to implement this using either the AJAX Control Toolkit or jQuery (leveraging jQueryUI), so you can implement it in whatever system you’re more comfortable with.
The Algorithm
On the client end, our logic is going to work like this.
- We create a flag called DoLogout that indicates whether or not to log the user out.
- Every X amount of minutes (we’ll call it TimeoutMinutes) we check to see if the DoLogout flag is set to 1. If so, we process our logout. If not, we’ll reset the flag and check again later. We’ll also do an arbitrary post back to the server so that we can make sure the server side session timeout is reset as well.
- Every Y amount of minutes, we warn the user (we’ll call it WarnMinutes) that they are about to time out, and ask them if they want to keep their session alive. If they say yes, then we set the DoLogout flag to 0, and we’ll warn the user again later.
Implementing the Client Processing
We’ll create a separate JavaScript file called TimeoutMethods.js and put all of our functionality in there. Here’s what it looks like:
var DoLogout = 1;
var WarnMills;
var TimeoutMills
var RedirectURL;
function StartTimeout(TimeoutValue, WarnValue, URLValue)
{
TimeoutMills = TimeoutValue;
WarnMills = WarnValue;
RedirectURL = URLValue;
setTimeout('UserTimeout()', TimeoutMills);
setTimeout('WarnTimeout()', WarnMills);
}
function UserTimeout()
{
if (DoLogout == 1)
{
top.location.href = RedirectURL;
}
else
{
DoLogout = 1;
setTimeout('UserTimeout()', TimeoutMills);
setTimeout('WarnTimeout()', WarnMills);
}
}
function WarnTimeout()
{
// To be updated later
}
function PreserveSession()
{
DoLogout = 0;
__doPostBack('btnPreserveSession', '');
}
Configuring and Registering the Timeout Code
<appSettings> <add key="AppTimeoutMinutes" value="3"/> <add key="AppWarnMinutes" value="1"/> <add key="AppLogoutURL" value="Logout.aspx"/> </appSettings>
<asp:ScriptManager ID="ScriptManager1" runat="server">
<Scripts>
<asp:ScriptReference Path="~/scripts/TimeoutMethods.js" />
</Scripts>
</asp:ScriptManager>
Protected Sub Page_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load
Dim AppTimeout As Integer
Dim WarnTimeout As Integer
Dim AppURL As String
If Not Request.Path.Contains("Login.aspx") AndAlso _
Not Request.Path.Contains("Logout.aspx") Then
AppTimeout = Convert.ToInt32(ConfigurationManager.AppSettings("AppTimeoutMinutes"))
WarnTimeout = Convert.ToInt32(ConfigurationManager.AppSettings("AppWarnMinutes"))
AppURL = ConfigurationManager.AppSettings("AppLogoutURL")
lblTimeoutCount.Text = (AppTimeout - WarnTimeout).ToString()
Page.ClientScript.RegisterStartupScript _
(Me.GetType, "InitTimeout", "StartTimeout(" & AppTimeout * 60000 & "," & WarnTimeout * 60000 & ",'" & AppURL & "');", True)
End If
End Sub
Warning Box using AJAX Control Toolkit
<%@ Register Assembly="AjaxControlToolkit" Namespace="AjaxControlToolkit" TagPrefix="cc1" %>
<asp:Panel ID="pnlSessionTimeout" runat="server" CssClass="TimeoutPanel" style="display: none;" Width="500">
<p>
Your session will expire in <asp:Label ID="lblTimeoutCount" runat="server" Text="[X]"></asp:Label> minutes due to inactivity.
<br /><br />
Please click the button below if you are still using the application.
</p>
<p style="text-align: center;">
<asp:Button ID="btnPreserveSession" runat="server" CausesValidation="false" Text="Preserve Session" />
</p>
</asp:Panel>
<cc1:ModalPopupExtender ID="mpeSessionTimeout" runat="server"
TargetControlID="pnlSessionTimeout"
BackgroundCssClass="TimeoutBackground"
BehaviorID="mdlSessionTimeout"
DropShadow="true"
OkControlID="btnPreserveSession"
OnOkScript="PreserveSession()"
PopupControlID="pnlSessionTimeout">
</cc1:ModalPopupExtender>
Warning Box using jQuery
<asp:ScriptManager ID="ScriptManager1" runat="server">
<Scripts>
<asp:ScriptReference Path="~/scripts/TimeoutMethods-jQuery.js" />
<asp:ScriptReference Path="~/scripts/jquery-1.4.1.min.js" />
<asp:ScriptReference Path="~/scripts/jquery-ui-1.8.11.custom.min.js" />
</Scripts>
</asp:ScriptManager>
<link href="~/styles/jquery-ui-1.8.11.custom.css" rel="stylesheet" type="text/css" />
<div id="TimeoutPanel" title="Timeout Warning" style="display: none;">
<p>
Your session will expire in <asp:Label ID="lblTimeoutCount" runat="server" Text="[X]"></asp:Label> minutes due to inactivity.
<br /><br />
Please click the button below if you are still using the application.
</p>
<p style="text-align: center;">
<asp:Button ID="btnPreserveSession" runat="server" CausesValidation="false" Text="Preserve Session" OnClientClick="PreserveSession()" />
</p>
</div>
$('#TimeoutPanel').dialog({ modal: true, closeText: '', width: 500 });


Thanks for the example just wondering it runs fine when no master page but when I implement one the J Query Dialogue appears with transparent background.
Hmmm, I wonder if maybe one of the images are missing when I zipped things up. If you look on the jQuery UI site, you can get the theme library to go with it. I forget the exact theme, but it is one of the first you find there.
Hi Dillie-O, thanks for your response. In you would have missed the image it would not have run in case of a page without master page. Your example runs fine without master page. I think there may me a problem when using master page. Can you please help me out this is exactly what I need and I am running out of time (and my boss out of patience) :)
Regards
Roy
Looks like there is some code missing in the web page….some of the snippets are showing blank
Thanks for the catch. The “angle bracket” type code gets tricky to format, even with the code formatter plugin. Things are fixed now.
Dillie-o: This is awesome! Exactly what I needed. Ran into one hiccup (or so I think). I have my warning set at 18 minutes and my timeout at 20. The modal pops up every 18 minutes, even if I’ve posted back to the server. I’ve registered the client script in my Master Page’s page load so that every time the server gets pinged, the client script would start over. Is that not the case? I’ve testd this by going from page to page within my app and within one page’s update panel that posts back based on different actions. Look forward to hearing your thoughts.
Greetings James! I’m glad this article helps! I’m slightly confused on your response, so let try to answer it and let me know if I’m missing something.
By default, whenever you do a full post back to the server (load a new page, have your GridView change paging without wrapping it up in AJAX/UpatePanel) the server side timeout is automatically refreshed (.Net handles this) and the client side timeout is refreshed since we reset the timeout on Page Load).
If you do a partial post back (say wrap a GridView in an UpdatePanel to retrieve data), the session is not reset, because a full post back is required to get the server session to reset itself (there’s some .Net documentation somewhere on this). In addition, the partial post back will not reset the client script, since we register that during the Page Load event.
I think the issue is just since you have actions occurring through your UpdatePanel, you aren’t getting a reset every time you perform an action within it. I’ll admit that part of this is by design, since I haven’t found a way to have AJAX related calls reset the server timeout value. There may be a way to do this, and I know there are client side methods you can hook into when an AJAX request is completed, so you may be able to do some research and improve the code even more to handle those situations.
If you do, I’d love to see the code!
Hope this helps. Please clarify anywhere I am off.
Thank you for your prompt response. You weren’t confused, you nailed it. Makes a lot of sense, I just wanted to make sure I wasn’t missing anything. I will certainly explore the options of having an ajax postback trigger a reset. If I find something I’ll be sure to let you know. Thanks again for this great example!
You’re quite welcome! I’m glad it helped!
Using the AJAX .NET design outlined here is there a way to make the timeout warning overlay appear to the user regardless of their IE session in focus. So mysite would warn my user even if they opened a new window/tab and went to amazon.com? Thanks
Greetings Lee. The current implementation does not do that, since we keep all of our “popup” messages within the page/tab itself. If you wanted to implement something like that, you would probably want to use a MessageBox type popup, since it creates a new window and can be displayed over the rest. Depending on how you implement this, you may wind up into security issues with the browser, since most browsers don’t like arbitrary windows popping up these days that weren’t initiated by the user. Hope this helps!
Would an alert fill the bill?
An alert box could potentially work, but you’re going to need to get some code in place to trigger some kind of server side postback after they click the button. I’m also unsure that if you are viewing tab B and tab A triggers the alert, if it will show up. It’s worth investigating.
This notification will work if the user is in a separate page in a child window. when the notification shows modally (at least in the JQuery version). Then the window will show up in front of the child window that is open. Even if the user is in an unrelated tab in a child window. However, it does not do so with tabs or with unrelated windows.
Thanks for checking into the child window issue! That is good to know. It makes sense that the tabs wouldn’t work, but it’s good to have this as a reference.
In the ajax version of this I get the error for the line $find(‘mdlSessionTimeout’).show(); js Microsoft Jscript Runtime error: ‘null’ is null or not an object
The only two places this value is mention on this page is in the BehaviorID of the Modal Popup Extender and in the javascript line so referenced. Any ideas on what may be causing this? Is it possible that mdlSessionTimeout should have been pnlSessionTimeout?
I believe you’re right. I could have put in a typo in the JavaScript call. I know the modal behavior and the actual targeted panel need to have separate values. Let me know if this works for you and I can update the blog accordingly.
I switched to the Jquery method. I also re-read the article and realized the $Find… was supposed to go inside of the WarnTimeout function. However I am still getting the same Jscript error on the last line on the js file. I am running in VS 2010 Visual Web Designer. would that make a difference?
Are you getting the error in Visual Studio or when you run the app? Sometimes the Intellisense isn’t the best in Visual Studio (though it has come a long way) and the best way to verify things would be through running the app and having Chrome Inspector or Firebug checking the JavaScript.
I run the app in debug and VS pops up a error message box saying Microsoft JScript runtime error: ‘null’ is null or not an object with break, continue, and ignore buttons. Pushing either continue or ignore result in the page loading but apparently without the javascript page. I threw some alerts into StartTimeout and WarnTimeout and Usertimeout, but they never fire. Interestingly enough, the error marker is always appearing on the same line of the file (the file not the code) so that as I add lines with alerts, the error marker moves further up in the code. Interestingly enough, the page always gets redirected to my Session dead page upon timeout even though the alert in UserTimeout never fires.
Hmm, that is odd indeed. What happens when you run it in non-debug mode?
Let’s do this, use the contact form and drop me an e-mail. We can keep this going through there, since it looks like the reply threshold is getting reached. Once we figure it out we can add a reply to the post letting others know in case they run into it.
Sorry it took so long to get back to you. I got pulled off of this task and was assigned to another. I just got back to work on this today. Now today strangely enough, none of those things happen anymore Everything runs as designed. How weird is that? I do have one question though. Some of our apps call child pages that openin the same session but in a separate window from the calling page. So the parent page will still be carrying out its countdown while work is being performed on the child page. So my question is will the modal JQueryUI or Modal Popup Extender open in such a way that it will open on top of the child page. The other issue I am addressing is if work is being carried out including postbacks how can you get the parent page to recognize that the server session has been renewed? Kenneth Scott suggested with his tool that the child page refresh call the reset function on the parent page when it reloads by using something like window.opener.PreserveSession() which would result in a postback of the parent page each time the child page reloads. I am not sure of the consquences of that if the parent page is depending on the child page for input, though I suppose it would be like having a dropdown set to autopostback. However what about AJAX callbacks or partial postbacks? Would this tool be able to recognized that the server session has been refreshed in this instance?
Greetings again! No worries on the delay. I know how it is when you’re pulled from one project to the other.
That is weird that everything is working. I know that sometimes Visual Studio does weird stuff with its Intellisense on occasion, and simply closing and opening Visual Studio again gets it all back into place. Maybe that was the case.
In regards to your question, if you have a child window pop open, it won’t be able to affect the parent window’s timeout by default. You’ll keep the server based timeout refreshed with each postback action you take, but the parent window will still have it’s client side (jQuery) timeout running. I like the potential of having the child window make a call to the parent’s refresh function. It sounds like it would work, let me know.
By default, AJAX calls don’t make a full post back to the server, so they won’t reset the server timeout check, which is why the way I have the reset timeout feature make a full postback.
I hope this helps!
Hi Dillie-O I have a theoretical question about AJAX partial post-backs. If the partial postbacks do not act as session \”keep alives\” then wouldn\’t that raise a problem with using Update panels on a complex website? Also one of the comments on Travis Collins\’ site concerning his tool mention a \”fix\” that would enable the tool to recognize Ajax partial postbacks as \”keep alives\”. However, wouldn\’t this be moot if the server doesn\’t recognize the AJAX call as something that indicates the session is still valid? It just doesn\’t seem logical that people would be encouraged to use a coding technique that doesn\’t let the server know the session is still active. Do you know where I can find something from MS that explains how the AJAX session/interaction?
You know, I had to do some looking around with this, because the last time I checked (admittedly quite a while back) AJAX posts weren’t able to keep the session details, so I would agree with you that it wouldn’t work for keeping the session alive.
However, after some more research, I found that it is possible to setup AJAX requests to preserve your session. I’ve seen two approaches that can make this happen.
One of them is to create a webmethod for the AJAX post back and use a directive to tell the method it needs the session details, which will effectively cause a full post back. You can see that here: http://stackoverflow.com/questions/7128268/how-to-reset-asp-net-session-with-ajax.
The other is to create an dummy HTTP handler which keeps your session alive. You can see that here: http://stackoverflow.com/questions/1431733/keeping-asp-net-session-open-alive.
Both options have some merit and it’s definitely worth looking into.
Calling the preserveSession() function from the child window in an client onload event function using window.opener.PreserveSession() worked out well.