A really cool feature that is part of the ASP.NET 3.5 Extensions release is the ability to add custom history points to a web application, both server-side and client-side. What do I mean by “history point”? We all know that when a user navigates through a website, each page they visit is logged by the browser (in their history), which allows them to go backwards and forwards (unless of course you used location.replace). This functionality is great and all, but the problem lies in the fact that history points are 1:1 with visited pages. With the advent of sophisticated JavaScript libraries, developers are more commonly providing advanced AJAX behavior in their web applications, many times performing lots of functionality on a single page. So really what is needed here is the ability to associate a history point with the state of a page, rather than just the page itself. This would enable two key scenarios:
- Users could use the browser’s back and forward buttons to essentially undo and redo work they’ve performed on the current page. Instead of navigating them to previously visited pages, it would navigate them to previously visited states of the current page.
- Users could bookmark the page at any state, allowing them to revisit the page at a later time and be presented with the same state they left off on.
The good news is that ASP.NET AJAX History easily enables both of those scenarios. In this article series, we’ll see how to leverage this new feature to create really cool user-experiences.
The scenario we’re going to be looking at is very a simple web application that allows users to pick their favorite NFL quarterback, out of a list of 10. Tom Brady is clearly the right answer, but because we live in a democratic nation, we’re going to leave the decision up to the user. It’s a pretty trivial exercise, but the cool part is that we’ll let people use the back and forward buttons to undo/redo their selections, as well as create a bookmark for their selection. In this article we’ll look at how to achieve this using the server-side API, then in the next article we’ll tackle performing this purely client-side.
I’m going to start by creating a simple BulletedList:

I obviously could have done this a number of different ways, but I haven’t used the BulletedList control in a while so I figured I’d throw caution to the wind and do something crazy. This code will render like so:

What I need to do is hook up some code to respond to the clicking of one of the links in the list, that will somehow visually display which quarterback is currently selected. I’ll add an event handler during the page’s initialization period:
protected override void OnInit(EventArgs e)
{
quarterbacksBulletedList.Click += this.quarterbacksBulletedList_Click;
base.OnInit(e);
}
And the code for the click event handler looks like so:
void quarterbacksBulletedList_Click(object sender, BulletedListEventArgs e)
{
string name = quarterbacksBulletedList.Items[e.Index].Text;
SelectQuarterback(quarterbacksBulletedList.Items[e.Index].Text);
}
All I’m doing here is grabbing the name of the user-selected quarterback, and then calling a method called SelectQuarterback that is responsible for actually visually depicting the quarterback as selected. The code for that method looks like so:
void SelectQuarterback(string name)
{
foreach (ListItem item in quarterbacksBulletedList.Items)
{
if (item.Text == name)
item.Attributes["class"] = "selected";
else if (item.Attributes["class"] != null)
item.Attributes.Remove("class");
}
}
All I’m doing is finding the item in the list that matches the user-selected name and adding a CSS class to it called “selected”. Because the user can change their selection, I have to also remove the “selected” class from any list items that were previously selected. There are probably numerous better ways to achieve this, but because this logic isn’t the focus of this article I’ll just leave it at that.
I create a new stylesheet and add the following style:
li
{
width: 10em;
}
li.selected
{
background: url(Selected.png) no-repeat center right;
}
This will add some formatting to our bulleted list, and display a nice graphic to the item that the user selects. Let’s run what we have so far and see how it looks. I select Tom Brady and I see the following:

I then select Tony Romo and I see the following:

I’d like to make this a little more “interactive” so I’ll add a ScriptManager control to the page and wrap our BulletedList control in an UpdatePanel:

If I run this, the app still runs the same, but without postbacks. Better, but not great. Because we are not posting back anymore, the browser no longer registers each “page visit” as a history point. Regardless how many different quarterbacks I select, I still see this (in IE7):

So how do we make it so that when we select a quarterback in the list it creates a new history point that can used to navigate back and forwards as well as bookmark a selection? The ScriptManager control includes a few new members, compliments of the AJAX History feature:
- Three properties: EnableHistory, EnableSecureHistoryState, and IsNavigating
- One method: AddHistoryPoint
- One event: Navigate
By setting EnableHistory to true you are telling the ScriptManager that you want the ability to add custom history points (we’ll cover EnableSecureHistoryState later). The IsNavigating property is a simple boolean that indicates whether a postback has occured due to a history navigation. Now that history is turned on, how do we actually add a history point? We use the ScriptManager’s new AddHistoryPoint method. The simplest version of this method takes a key and a value (or state). It requires a key because you can add many different history points to a page, and it needs a way to seperate them. In our case we are only adding a single history point to the page: favorite quarterback. We need to determine what user action represents a good place to create a history point. For this exercise, the clicking of an item in the bulleted list makes the most sense, so let’s modify the list’s click event handler:
void quarterbacksBulletedList_Click(object sender, BulletedListEventArgs e)
{
string name = quarterbacksBulletedList.Items[e.Index].Text;
scriptManager.AddHistoryPoint("FavoriteQuarterback", name);
SelectQuarterback(quarterbacksBulletedList.Items[e.Index].Text);
}
Notice that the only thing we changed is that we’re now calling the AddHistoryPoint method, which we’re just passing the name of the selected quarterback. Now every time a user selects a different quarterback, we’ll be registering a history point for that selection which allows them to move back and forwards. Note that the AddHistoryPoint has two other overloads, both of which also accept a title parameter. The title parameter allows you to associate a page title with a history point, that will be displayed as the browser’s title when the user navigates to that history point via the back and forward buttons. This is a really cool feature, so we’ll modify our call to AddHistoryPoint like so:
scriptManager.AddHistoryPoint("FavoriteQuarterback", name, "Favorite Quarterback: " + name);
The AddHistoryPoint method has one final overload which allows you to pass a NameValueCollection instead of a single key/value pair. This is good if you have numerous history points you want to add (i.e. favorite quarterback, favortie running back, etc). It also takes a page title as well.
If we run this app right now and click on Tom Brady, our browser navigation buttons suddenly come alive:

Awesome, now my app is working perfectly and registering each selection as a point in history. If I were to click the back button at this point nothing would happen, and you might be wondering why. We’re successfully adding history points now, but since the data we provide as the history state is completely arbitrary, the app has no idea what to do with it. This is an important point to note: the history points we create are not coupled to the actual page in any way. When we call AddHistoryPoint, we’re not snapshoting the current page’s look and feel, we’re storing just enough data that allows us to recreate the page state, and letting the ScriptManager tell the browser about it. This is one of the reasons why I love the AJAX History because it’s so clean and simple. In fact, this raises the question, how exactly is it registering the history points? How does the AJAX History feature make the browser treat your user-interactions as history points?
Let’s take a look at the URL of the app when we first run it: http://localhost:49652/Default.aspx. Pretty standard stuff. Now let’s click on Tom Brady and then look at the URL:
http://localhost:49652/Default.aspx#&&/wEXAQUTRmF2b3JpdGVRdWFydGVyYmFjawUJVG9tIEJyYWR5gAd6kNVm8xxyN9OxXaQE0P8MvLY=.
Wow, that is a big difference! If you notice, directly after the page name (Default.aspx) we see a hash mark (#) which is followed by a long string a funky looking text. You may recall that the hash mark is used to navigate to a specific <a> on a page. So if I had a webpage with an <a> element whose ID was set to “link”, I could request the page with “#link” and it would scroll down the page to where the <a> element resided. Nothing new here. What’s great is that using the hash mark to navigate the current page doesn’t cause a postback to occur, since you’re essentially telling the browser that you’d like to move to another place on this page and there is no need for a server request. This is how AJAX History is able to create custom history points for you, and navigate through them without posting back. It’s a simple yet elegant solution if you ask me
So what is the deal with the long string of text? By default when you call AddHistoryPoint, the ScriptManager will hash your key/value pair before creating the actual history point. This is in case you are storing sensitive data, at which point they’re opting for security by default. For the most part I couldn’t see myself putting secure data in a URL anyways, so I’d prefer to turn this hashing off. This is where the ScriptManager’s EnableSecureHistoryState property comes in. If I set that to false and rerun the app, selecting Tom Brady, my URL is now:
http://localhost:49652/Default.aspx#&&FavoriteQuarterback=Tom+Brady.
That’s certainly a lot cleaner. It’s pretty clear now how our call to AddHistoryPoint translates into a URL. “FavoriteQuarterback” was our key, and “Tom Brady” was our value. All it did was URL encode it and add it to the URL’s hash. The last point of interest is the double ampersand (&&) in the URL. This is there because you can set history points from both the client and server side, and they need to be differentiated. All server-side history points follow the double ampersand, and client-side history points preceed the double ampersand. We’ll see more of this in the next article.
Alright, back to business. Now that we’ve got our history points in place, and we understand how the ScriptManager is translating those points into something the browser can understand, how do we tell our app how to interpret the history points when they are navigated to. When I hit the back button, how does my app know how to recreate the page at the specified state? This is where the ScriptManager’s new Navigate event comes in. This event is fired whenever a page is requested with state data in the URL (#&&key=value) and state is turned on (via the EnableHistory property). This means that when a user hits the back or forward button, which navigates to a URL with state information, the Navigate event will fire. This also means that if a user bookmarks a history point and then comes back to it later, the Navigate event will fire (because the bookmarked URL would have the state in it).
I’m going to modify the page’s initialization method to include the registration of the Navigate event like so:
protected override void OnInit(EventArgs e)
{
quarterbacksBulletedList.Click += this.quarterbacksBulletedList_Click;
scriptManager.Navigate += this.Navigate;
base.OnInit(e);
}
And I’ll implement the Navigate method like so:
void Navigate(object sender, HistoryEventArgs e)
{
SelectQuarterback(e.State["FavoriteQuarterback"]);
}
All I’m doing here is calling the same method that is called when a list item is clicked, but I’m passing in the value from the state. This is where the key of your state comes into play, because you later need some way to retrieve that value.
I run the app and select Tom Brady:

I then select Eli Manning:

I then realize that Eli Manning is actually a really lame quarterback, so I hit the browser’s back button, and once again Tom Brady is selected. If I hit the forward button, you’ll notice that Eli Manning is once again selected. I could select different quarterbacks all day long and I’d still be able to move backwards and forwards with ease.
I’m going to select Matt Hasselbeck (go Seattle!) and bookmark the page, which stores this URL: http://localhost:49652/Default.aspx#&&FavoriteQuarterback=Matt+Hasselbeck. I’ll open up another instance of IE and navigate directly to my bookmark:

How sweet is that! With just a few lines of code we’ve turned our little list into an easy to use app complete with AJAX and history points. In the next article we’ll see how to achieve this using the ASP.NET AJAX library.