10 Notes™

TEL 202.553.4000 FAX 202.280.1341 info@10notes.com

Blog

Create a Stateful Timer Control with AJAX.NET

Posted on Nov-04 2007 @11:11 am

I’m creating a meeting registration system for one of my clients. This association offers its membership hundreds of poster sessions and workshops at the meeting. We’re using .NET 2.0 and SQL Server to create a shopping cart for the registration system, as well as a multi-page checkout module. While coding the GUI for the checkout area, I ran across a timer control feature that seemed blog-worthy.

View the demo · Download the source code

Demo Application - Screenshot

1. The Requirement

The designer for the system has added a timer feature to the checkout area; the timer starts when the user begins the checkout process. Throughout this multi-step process, the timer lets the user know that they have 30 minutes to finalize their registration, then counts down accordingly. At the database level, this effectively translates to row-level locking for the products in the user’s shopping cart; other users in the system will not be allowed to reserve that particular seat when adding workshops to their own shopping carts. (You’ve probably seen this feature in airline ticket reservation systems.)

As an added wrinkle, the client requested that if the timer expires, the system should prompt the user to refresh the session, re-start the timer, and allow the user to continue the checkout process.

2. The Approach

I’m using the AJAX.NET controls all over the place in this meeting registration system. For the timer feature, I elected to use the framework’s built-in Timer control, which basically AJAX-izes (sp?) the low level System.Timers classes. Out of the box, the Timer control doesn’t provide any graphic parameters, nor does it provide statefulness. The Timer control simply provides an Interval parameter (in milliseconds) and the ability to quickly implement asynchronous postback events back to the server-side code.

Since my requirements call for the timer to be persistent across multiple pages in the checkout process, I decided to create a user control that (A) maintained a session-based variable for the elapsed time, and (B) dynamically adjusted the interface to reflect the elapsed time. Additionally, the user control needed to handle the “timeout prompt” described above. (Respectively, “ajaxTimer1″ and “ajaxTimer2″ hereafter.)

Here’s the .ascx code for the user control:

<asp:UpdatePanel ID="ajaxPanel" runat="server">
	<ContentTemplate>
		<asp:Timer ID="ajaxTimer1" runat="server" Interval="1000" OnTick="ajaxTimer1_Tick" />
		<p>You have <asp:Literal ID="litTimeout" runat="server" /> to complete this application.</p>
		<div>
			Time elapsed: <span class="progress"><asp:Literal ID="litProgress" runat="server" /></span>
			<table id="tblProgress" runat="server" cellpadding="0" cellspacing="0" class="progress">
			<tr><td>&nbsp;</td><td>&nbsp;</td><td>&nbsp;</td><td>&nbsp;</td><td>&nbsp;</td></tr>
			</table>
		</div>
		<asp:PlaceHolder ID="plcTimeout" runat="server" Visible="False">
			<div class="timeout">
				<asp:Timer ID="ajaxTimer2" runat="server" Interval="1000" Enabled="False" OnTick="ajaxTimer2_Tick" />
				<p>The timeout for the operation has expired. Press the &quot;Continue&quot; button in the next <asp:Literal ID="litResponseTime" runat="server" /> seconds to refresh your session.</p>
				<p><asp:Button ID="btnContinue" runat="server" Text="Continue" CssClass="btn" CausesValidation="False" OnClick="btnContinue_Click" /></p>
				<asp:Literal ID="litResponseTimeout" runat="server" Visible="False" Text="<p>You have not responded in the time allotted. Your session has now expired.</p>" />
			</div>
		</asp:PlaceHolder>
	</ContentTemplate>
</asp:UpdatePanel>

As you can see, I’ve wrapped both Timer controls in an UpdatePanel. Additionally, the .aspx page where the control lives includes the ScriptManager tag, which tells AJAX.NET to create JSON converters for any controls defined inside of the UpdatePanel’s ContentTemplate. After installing the framework and adding all of the necessary Web.config stuff, that’s pretty much the long and short of creating any AJAX.NET application…pretty easy, huh?


The next step was to define 2 session vars in the .ascx codefile, 1 to store the time elapsed as incremented by ajaxTimer1, and 1 to store the response timeout as decremented by ajaxTimer2.

Here’s the short version of the ajaxTimer1_Tick and ajaxTimer_2 Tick events, where msTimeElapsed references the 1st session var and msTimeoutResponse references the 2nd response timeout session var:

protected void ajaxTimer1_Tick(object sender, EventArgs e)
{
	this.msTimeElapsed = this.msTimeElapsed + ajaxTimer1.Interval;
	this.PrintElapsedTime();
}

protected void ajaxTimer2_Tick(object sender, EventArgs e)
{
	this.msTimeoutResponse = this.msTimeoutResponse - ajaxTimer2.Interval;
	this.PrintResponseTime();
}

All of the show/hide GUI logic is defined in the PrintElapsedTime and PrintResponseTime methods. PrintResponseTime is also responsible for tearing down the registration session if the user didn’t respond to the prompt. After that, I simply registered my user control on each screen of the registration module, then added all of the required form elements to each screen. Take a look at the demo to see this in action…hopefully this illustrates how to extend baked-in AJAX.NET functionality for creating rich GUI features to handle some of the goofy business logic in your own .NET applications. Thanks for reading!

View the demo · Download the source code

« CaptologyUpdates (finally!) »

1 Comment

 

Comment by Andre P., Jan-28 2008 @12:44 pm

I think your approach is overly complicated, and doesn’t allow for “true time”. If you store the time/date that a session was started/reset, then you’d simply have to calculate the elapsed time as a difference instead of a sum. A clever user could easily discern your timeout mechanism in page source, and use that knowledge to prolong the timeout indefinitely. Storing the absolute start of session in a global location would also allow you to determine when a session has timed out, independent of the other sessions returning data or not.

RSS feed for comments on this post
TrackBack URL

(will not be published)
TEL 202.553.4000 · FAX 202.280.1341 · info@10notes.com · 1510 Park Rd, NW, Suite 1 · Washington, DC 20010
Copyright © 2008, 10 Notes, LLC. All Rights Reserved.