ASP.NET Ajax AddHistoryPoint Bug
In .NET Framework SP1 there was a great feature added that allows history points to be added for Javascript changes. This means, you can use the browswer back/forward buttons with Javascript changes on the page.
When released, I went to implement it, and quickly found there is a bug that causes this feature to not work at all in IE.
Problem:
To use this feature on the client, you enable it by setting EnableHistory="true" on the ScriptManager. What this does is renders "Sys.Application._enableHistoryInScriptManager();" right before it renders "Sys.Application.initialize();" on the page. To create a history point, you call "Sys.Application.addHistoryPoint(state, title);". You then subscribe to an event "Sys.Application.add_navigate". This event should fire every time "addHistoryPoint is called, and every time the page navigation is clicked within the current history.
The problem is, with IE there is an iframe tag rendered that has this code in it "parent.Sys.Application._onIFrameLoad();". If the iframe loads before the parent page has rendered and the "Sys.Application._enableHistoryInScriptManager();" method has been called, the navigate event never gets called, and you can't recreate the state on your page.
Solution:
I submitted a support incident to Microsoft to get this issue resolved. The person helping me confirmed it was a bug and passed it on to the ASP.NET team to check it's validity. I didn't hear anything back for several weeks. This past week I was at PDC and decided to ask Bertrand LeRoy about it, since he's the creator of this feature. He was able to recreate the problem, and sent an email off to get a bug issued.
Today I get a call from MS Support and was told that this issue was fixed in IE8, but not in IE7 or IE6 and they expect their customers to move to IE8 so they're not going to worry about IE6/7.
This is really sad considering IE8 hasn't even been released yet, and IE6/7 are still supported. This makes it pretty much impossible for me to implement this feature. I can't expect my users to upgrade to a browser that is still in beta. According to wschools, as of October 2008, IE6 still holds 20.2% of the market and IE7 holds 26.9%.
To get this problem to occur, there needs to be enough stuff on the page going on for the iframe to load before the bottom of the parent page loads. The page where I'm seeing this issue is around 400k, give or take 100k. This is a fairly large page, but there is a lot of content and javascript going on withing the page, and there isn't much room for trimming. An easy way recreate it is to just add a whole bunch of garbage text to the page. With this method the page ends up being around 7-8MB before you see the issue occur. Again, I see it at 400k.
Sample:
<%@ Page Language="C#" AutoEventWireup="true" CodeBehind="Default.aspx.cs" Inherits="HistoryNavigationProblem._Default" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" >
<head runat="server">
<title></title>
</head>
<body>
<form id="form1" runat="server">
<asp:ScriptManager runat="server" ID="scriptManager" EnableHistory="true"></asp:ScriptManager>
<script type="text/javascript">
Sys.Application.add_init(pageInit);
function pageInit(sender, e)
{
Sys.Application.add_navigate(navigateHandler);
$addHandler($get("<%= this.button.ClientID %>"), "click", buttonClickHandler);
}
function navigateHandler(sender, e)
{
var label = $get("<%= this.label.ClientID %>");
label.innerHTML = e.get_state().text;
}
function buttonClickHandler(event)
{
event.stopPropagation();
event.preventDefault();
var label = $get("<%= this.label.ClientID %>");
var text = $get("<%= this.text.ClientID %>");
Sys.Application.addHistoryPoint({ text: text.value });
text.value = "";
}
</script>
<asp:Panel runat="server" DefaultButton="button">
<asp:Label runat="server" ID="label"></asp:Label>
<asp:TextBox runat="server" ID="text"></asp:TextBox>
<asp:Button runat="server" ID="button" Text="Add" />
</asp:Panel>
<asp:Label runat="server" ID="lblJunk"></asp:Label>
</form>
</body>
</html>
[Edit]
Bertrand LeRoy has confirmed that this bug is not closed, and they're planning on releasing a fix for IE6/7 with the next .NET release. MS Support was wrong.
Thanks Bertrand!