Today I’ve had an extremely interesting realization: the number, order and exact point in the page lifecycle at which HtmlMeta controls are added to the HTML head can have significant implications for your page. Especially if you have some sort of “transient” meta tags that are only added to the page when it is initially loaded, but not after a postback. When you call the
myHeadControl.Controls.Add(myHtmlMetaControl)
method, every control that doesn’t have a manually set ID will be assigned an automatic ID by its naming container (ctl00, ctl01, …). This doesn’t seem too bad until you realize that this means that the ID of your very important custom control can change from “…ctl08…” during initial page load to “…ctl04…” in a postback. And THAT is a problem. Because the way that the view state is restored to the control tree is directly through those control IDs. Actual results can vary from mismatched control values to view state exceptions and lots of other hard-to-trace problems.
After careful reflection over that problem (that means: using Red Gate’s .NET Reflector to analyze the .NET Framework) I arrived at the following solution for the problem:
Since HtmlMeta tags really don’t need an ID, I wanted to disable those auto-generated IDs. The easiest way to do that is of course to manually set an ID for every HtmlMeta control. Unfortunately this has the side effect that every meta tag also has an ID attribute in the generated HTML code. Looking through the source code that generates those control IDs, I stumbled upon the
System.Web.UI.Control.PreventAutoID()
method which does exactly what I need – it sets an internal flag that disables the auto-ID generation. Naturally, this method is internal -.-
Usually I’m a very strong supporter of clear APIs and information hiding, but in this case I think my use case is valid and that this method should be public. So….. I did what every slightly insane developer would have done in my place; reflect and invoke.
private static MethodInfo _preventAutoIdMethod; private static void PreventAutoId(Control control) { if (_preventAutoIdMethod == null) { _preventAutoIdMethod = typeof (Control).GetMethod("PreventAutoID", BindingFlags.Instance | BindingFlags.NonPublic); if (_preventAutoIdMethod == null) throw new Exception("Who dereleased the .NET Framework method System.Web.UI.Control.PreventAutoID?"); } _preventAutoIdMethod.Invoke(control, null); }
I added some more snarky comments, et voilà: no more auto generated IDs for my HtmlMeta controls.