Published: 11 Jan 2008
By: Dino Esposito

Dino Esposito continues his examination of the ASP.NET AJAX History control.


By design, AJAX applications tend to do most of their tasks within the same page without changing the URL. This makes it quite complicated for a browser to track any distinct states the application transits. History points are an attempt to add history support to ASP.NET AJAX applications. In this article, I'll examine the client-side API in ASP.NET 3.5 Extensions.

History Points

A "history point" is a logical step in an ASP.NET AJAX application that you want to be able to return to at some point in the application lifetime. You create a "history point" by associating some state information with the current page URL. The ASP.NET AJAX runtime then manages to save a mangled URL to the browser's cache of Back/Forward navigation points so that those application-specific history points are displayed to the users in the menu of recently visited URLs.

From a programmer's standpoint, you create a history point by using some new methods defined in the ScriptManager class of ASP.NET 3.5 Extensions. You may invoke this extended API from many places, but typically you create a history point in an event handler when you detect that you are in a state you want to return later - for example, page 4 of a pageable grid.

In a previous article on DotNetSlackers, I covered the server-side API for adding history points. Basically, in that article I discussed the methods and techniques you need to use to save a history point in the handling of a server event. But a similar API also exists for the client-side events that you handle using JavaScript code.

Enabling History Management

To enable history management, be it for server-side or client-side programming, you need to set the EnableHistory property to true on the ScriptManager control. If you're in the context of a master page, then you might want to use ScriptManagerProxy instead. This setting enables the download on the client of proper JavaScript code that contains the client-side classes for history management.

It should be noted that a trick is required to add the history point to the browser's list of recently visited URLs. No browsers, in fact, do offer a programmatic API to add new URLs to the list. The Microsoft script code performs browser-specific tricks that basically consist of forcing the browser to navigate to the mangled URL in a way that doesn't affect the user. For Internet Explorer, in particular, the trick consists in the creation of an invisible IFRAME that downloads the mangled URL, thus adding it automatically to the list of visited URLs.

Creating Client History Points

You add a client history point in a JavaScript function associated with a user event - for example, a button click. Imagine an ASP.NET AJAX page that invokes a remote Web service to grab information about a customer.

In the sample code, you select an item from a drop-down list and pass it to a JavaScript helper that invokes a remote Web service. Immediately after firing the call, you save the history point. You use the Sys.Application.addHistoryPoint method to define the history point. The method allows you to define the URL as well as the title to appear in the browser list. The URL is mangled with page-specific state information that will be passed back to your code when the user navigates back to the URL from the browser's history.

In general, state information is a collection of key/value pairs. In this case, the state is a single piece of data - the customer ID. The preceding code snippet produces the graphical effect depicted in Figure 1.

Figure 1: Custom titles in the browser’s history list


Each history point is characterized by a modified URL and a title in the browser's history list. The URL is modified as below:

It is worth noting that what follows the # symbol is the serialization of the state information you provided when you created the history point. You can use the following code to create a permanent link to the state:

Now that you know how to save history points, it is about time to figure out how to restore a previously reached state.

Restoring a State from a History Point

The Sys.Application JavaScript class kicks in whenever the page being displayed has a URL whose pattern matches the mangled URL of history points. When such a page is navigated by the user, the navigate event is fired to the client code. You need to add a handler for this event. A possible place where you can do this is the pageLoad function - an ASP.NET AJAX function that, if present, executes when the page's client-side object model has been fully initialized.

In the handler for the Sys.Application.navigate event, you first retrieve the saved state string and then restore the proper application's state - whatever that means for the current page. For this service, you can't rely on any predefined browser or library behavior. In the previous code snippet, all this logic is contained in the restorePage helper function.

It is worth noting that the navigate event is also fired when you add a history point and not just when a URL that contains history state is navigated by the user. This may pose an issue if you need to perform potentially heavy operations to restore the state. Consider the previous example.

In the event handler you make a roundtrip to the server to download customer information. Next, when a previously saved page is navigated again, you restore the state. To restore customer information, though, you reasonably need to repeat the remote access. This means that, unless you take countermeasures, you make a first roundtrip when you add a history point and repeat it immediately after when the navigate event is fired. This is not an issue if you use cached data to restore the state, but it is a point to be kept in mind just in case.

You can use a Boolean global variable to track whether the navigate event is fired from within the context of a call to addHistoryPoint.

You set the Boolean variable just before you add the history point. In this way, it is set when the navigate event subsequent to marking the history is fired. As a result, no state is restored. Immediately after adding the history point, you reset the variable.

Next, when the user navigates to the history point, the variable is not set and the state associated with the history point is correctly restored.

The navigate Event

The navigate event requires a handler with the following prototype.

The sender argument is the Sys.Application object of the current page. The e argument evaluates to an instance of the HistoryEventArgs class defined in the version of the Microsoft AJAX library that ships with ASP.NET 3.5 Extensions. The HistoryEventArgs class features one key property - state.

Just as any property defined on classes in the Microsoft AJAX library, the state property is accessed using a get method accessor - get_state. The state property returns a name/value collection that represents the state. In this example, I used a collection with just one entry, but you're allowed to use as many entries as required by the logic you intend to implement.

Note: The navigate event is also fired if a portion of the page is involved in a partial refresh conducted through an UpdatePanel control.


History points are a key enhancement for AJAX applications. They keep AJAX pages usable through Back and Forward browser buttons and also help the page to be ranked by search engines. ASP.NET 3.5 Extensions develops a programming model that is nearly the same on both the client and the server meaning that you can use this model with both managed languages such as C# and JavaScript.

All that you have to do is invoking a method that adds a history point when in your client or server code you find a state that you want to be able to return. You provide a name/value collection of information that identify that state uniquely and, at the same time, is informative enough to let you run code to restore the state entirely. A mangled URL is added to the browser's navigation stack and whenever the user navigates to such a URL an event is fired to your server and client code. The event carries the same state information you previously saved and gives you a chance to restore the desired state.

<<  Previous Article Continue reading and see our next or previous articles Next Article >>

About Dino Esposito

Dino Esposito is one of the world's authorities on Web technology and software architecture. Dino published an array of books, most of which are considered state-of-the-art in their respective areas. His most recent books are “Microsoft ® .NET: Architecting Applications for the Enterprise” and “...

This author has published 54 articles on DotNetSlackers. View other articles or the complete profile here.

Other articles in this category

Animating a Web Form using ASP.NET AJAX
In this article you will learn how to animate a webform using ajax.
Jquery Ajax
JQuery makes communicating with the server very, very easy. JQuery uses get(), getJSON(), and post(...
jQuery Deferred Objects Promise Callbacks
jQuery Deferred/Promise objects untangle spaghetti-like asynchronous code.
jQuery in Action 2nd edition: Queuing functions for execution
This article is taken from the book jQuery in Action, second edition. This segment shows how you can...
This is my custom article

You might also be interested in the following related blog posts

ClientIDMode in ASP.NET 4.0 read more
Notify Client Applications Using WCF Callbacks read more
WebResource access in ASP.NET MVC read more
Silverlight 3 and WCF Faults read more
Problems with the clientaccesspolicy.xml for Silverlight access to HTTPS read more
You should NOT use ASP.NET MVC if. . . read more
Designing AD for a 3-Tier Application read more
Implementing a WCF service firewall part II of N read more
Fluent Interfaces and Flowcharts read more
Utilizing the Microsoft AJAX Framework and ClientAPI to Develop Rich Modules: Part II read more


Subject Author Date
placeholder Nice article! Granville Barnett 1/15/2008 5:36 PM
Excellent Haissam Abdul Malak 1/24/2008 4:21 PM
placeholder add_navigate should be done during init Bertrand Le Roy 1/30/2008 7:14 PM
Interesting Read Patrick Smith 1/31/2008 12:15 AM

Please login to rate or to leave a comment.