June 21, 2006
Microsoft ASP.Net 1.1 has a bug that will bite you when you least suspect it.
http://support.microsoft.com/default.aspx?scid=kb;en-us;817032
Basically, if your web application has more than 8 different pieces of client-side script registered using RegisterClientScriptBlock in a given web request, then the order in which they are registered gets lost. It’s fine up through and including the 8th registration, but as soon as you register the 9th, the order of all of them becomes randomized.
Anyone who has created a large complex website will surely ask, “ONLY 8?!”. Yes, just 8, easily surpassed simply by having several web controls each with their own little piece of client-side script. A clock control, a shopping-cart, some validation script, etc. and before you know it, it’s all jumbled.
Now, as long as each script is totally self-contained, you’re okay — nothing broken. But, suppose one of the scripts relies on variables defined in one of the other scripts, or some other condition that makes it necessary to register the scripts in a specific order. In that case, the sudden randomization when you hit #9 is a real problem.
The MSDN article provides a hint at how to fix the problem. However, it assumes you will have all of your client script registration happening in one place. A better alternative is one that doesn’t require you to modify a dozen different places in the code.
The solution I will describe assumes that, with your large ASP.net 1.1 application, you are using a class derived from web.ui.page. From this class, you derive all other pages in your web site (this is the best way to build a complex site, after all). We’re a little lucky that the RegisterClientScriptBlock function is overridable (YAY, some forward thinking at Microsoft). But, (Oh, No!) IsClientScriptBlockRegistered is not overridable (Boooo, these functions are a set. Why would they make one overridable and not the other?! *gasp*).
Anyway, in your base page, override RegisterClientScriptBlock and tack on all the script that gets registered into a single stringbuilder class level variable. Then, call mybase RegisterClientScriptBlock with a dummy string of meaningless HTML comment text, so that the web.ui.page classes’ IsClientScriptBlockRegistered will return the proper true value when the caller checks.
Private sbRegisteredScripts As StringBuilder = New StringBuilder(“”)
Public Overloads Overrides Sub RegisterClientScriptBlock(ByVal key As String, ByVal script As String)
Try
If IsClientScriptBlockRegistered(key) Then Return
sbRegisteredScripts.Append(script)
mybase.RegisterClientScriptBlock(key, “<!— registered “ & key & “ à” )
Catch ex As Exception
‘ standard error handling for your app
End Try
End Sub
After that override the OnPreRender function and (after checking to make sure the string isn’t empty) call RegisterClientScriptBlock, passing it the concatenated string of all the registered scripts.
Protected Overrides Sub OnPreRender(ByVal e As System.EventArgs)
Try
Dim sTemp As String = sbRegisteredScripts.ToString()
If Len(sTemp) > 0 Then
MyBase.RegisterClientScriptBlock(“some unique value”, sTemp)
End If
sbRegisteredScripts = New StringBuilder(“”)
Catch ex As Exception
‘ standard error handling for your app
Finally
MyBase.OnPreRender(e) ‘ DON’t FORGET THIS LINE
End Try
End Sub
With this solution, you don’t have to change any of the individual controls or pages that register script, and all your script will be in one neat chunk all in the proper order.
Follow