Soup to Nuts: Creating a Timeout Notifier in ASP.Net using AJAX Toolkit or jQuery

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.

  1. We create a flag called DoLogout that indicates whether or not to log the user out.
  2. 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.
  3. 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', '');
 }
Note: I’m leaving the WarnTimeout() function blank for now, because this function will differ slightly based on your AJAX or jQuery implementation. Notice how our StartTimeout function serves as the gateway to our timeout implementation. This allows us to easily register a single JavaScript code block and to configure out timeout variables in a web.config file.

Configuring and Registering the Timeout Code

In our web.config file, we add the following application settings in order to appSettings section so we can reconfigure things on the fly:
<appSettings>
   <add key="AppTimeoutMinutes" value="3"/>
   <add key="AppWarnMinutes" value="1"/>
   <add key="AppLogoutURL" value="Logout.aspx"/>
</appSettings>
Notice that you can effectively disable the warning event (should you desire) by setting the value larger than the timeout value. This is helpful if you just want to log the user out of the application without warning.
Since the JavaScript code is in an external file, we need to make sure that it is properly loaded on the page. It is best to load it using the ScriptManager that is provided in ASP.Net AJAX WebApplications. You’ll find it right below the <form> tag in the web page you create, and you simply update the section accordingly:
<asp:ScriptManager ID="ScriptManager1" runat="server">
    <Scripts>
        <asp:ScriptReference Path="~/scripts/TimeoutMethods.js" />
    </Scripts>
</asp:ScriptManager>
The final step is to register the timeout code to run when the page is loaded. Update your Page_Load method accordingly.
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(&quot;Login.aspx&quot;) AndAlso _
      Not Request.Path.Contains(&quot;Logout.aspx&quot;) Then

      AppTimeout = Convert.ToInt32(ConfigurationManager.AppSettings(&quot;AppTimeoutMinutes&quot;))
      WarnTimeout = Convert.ToInt32(ConfigurationManager.AppSettings(&quot;AppWarnMinutes&quot;))
      AppURL = ConfigurationManager.AppSettings(&quot;AppLogoutURL&quot;)

      lblTimeoutCount.Text = (AppTimeout - WarnTimeout).ToString()

      Page.ClientScript.RegisterStartupScript _
           (Me.GetType, &quot;InitTimeout&quot;, &quot;StartTimeout(&quot; &amp; AppTimeout * 60000 &amp; &quot;,&quot; &amp; WarnTimeout * 60000 &amp; &quot;,'&quot; &amp; AppURL &amp; &quot;');&quot;, True)
   End If
End Sub
Note that since JavaScript processes the timeout calculation in milliseconds, we need to pass it millisecond values to the StartTimeout method.
You’ll notice a couple of odd things here. First is why we’re checking to see if the request path is Login.aspx or Logout.aspx. This code is here to demonstrate how you can use this as part of a MasterPage type setup. That way you can keep your Login/Logout pages using the same template as the rest of your application, but avoid having the timeout scripts run. The second is the lblTimeoutCount.Text statement in there. We’ll get to that shortly.
Now that the script is ready to go, the final step is to setup our modal warning box, based on the display framework we want to use.

Warning Box using AJAX Control Toolkit

What we need to do is create a panel that contains our warning message and then attach a ModalPopupExtender to this panel. If it hasn’t been done already, the AJAX Control Toolkit is added as a reference to the application and we make sure the assembly is registered at the top of our page.
<%@ Register Assembly="AjaxControlToolkit" Namespace="AjaxControlToolkit" TagPrefix="cc1" %>
We add this to the bottom of the page, before the closing <form> tag, and you can see the stylesheet for the styling done to the popup:
<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>
From here, we update our WarnTimeout method in our JavaScript file to include the following method to trigger our modal popup:
$find(‘mdlSessionTimeout’).show();

You’re all set! Build the app, navigate to the page and wait for the notification to appear:

Warning Box using jQuery

The jQuery and jQueryUI libraries already have a modal dialog plugin that operates simple as well. After downloading the two libraries and placing them within your application (don’t forget the image files that comes as part of jQueryUI) make sure to reference them accordingly.
In our Scripts section of our ScriptManager we add:
<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>
In the <head> section of our page we add:
<link href="~/styles/jquery-ui-1.8.11.custom.css" rel="stylesheet" type="text/css" />
Then we add a div section to the bottom of the page, before the closing <form> tag, and there is no need to use stylesheets thanks to the styling built into jQueryUI
<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>
Finally, we update our WarnTimeout method in our JavaScript file to include the following method to trigger our modal popup:
$('#TimeoutPanel').dialog({ modal: true, closeText: '', width: 500 });
You’re all set! Build the app, navigate to the page and wait for the notification to appear:

Conclusion

I hope this bit of code helps you get your own sites off the ground that need a Timeout mechanism for it. Its tricky keeping track of the session on the client and server end, and this script does the job nicely. Attached below is a full project for you to build and work with. It runs in VB.Net, but there’s only about 3 lines of code behind involved and is easily converted to C#.
Download Project Files:
Visual Studio 2008 –  Download
Visual Studio 2010 – Download
About these ads

29 thoughts on “Soup to Nuts: Creating a Timeout Notifier in ASP.Net using AJAX Toolkit or jQuery

  1. Roy says:

    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.

  2. 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.

  3. 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

  4. James says:

    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.

      • James says:

        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!

  5. Lee says:

    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!

        • 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.

  6. Edward Joell says:

    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.

      • Edward Joell says:

        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.

          • Edward Joell says:

            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.

  7. Calling the preserveSession() function from the child window in an client onload event function using window.opener.PreserveSession() worked out well.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s