Now its turn to peek at how <meta> child elements are being supported. Let’s take for example the following markup:
<head runat=”server”>
<title>Foo</title>
<meta name=”one” content=”uno” />
</head>
As the <head> element has a proper runat=”server” attribute, it will be parsed as an instance of HtmlHead and you will be able to programmatically play with it at runtime like this:
this.Header.Metadata.Add (“two”,”dos”);
What output would you expect from the previous code?
This one:
<head runat=”server”>
<title>Foo</title>
<meta name=”one” content=”uno” />
<meta name=”two” content=”dos” />
</head>
Or this other real funny one:
<head runat=”server”>
<meta name=”one” content=”uno” />
<title>Foo</title>
<meta name=”two” content=”dos” />
</head>
Of course you should expect the first one, but with the March04 preview bits you’ll get the second one.
What causes this strange reordering of the tags? Uff... I mean… once we finally got VS.NET to *never* touch our markup now it’s the HtmlHead control that decides to rearrange them in the previously shown “clever” way of meta-title-meta…
Let’s try to shed some light on what’s happening here…
HtmlHead has associated a control builder, HtmlHeadBuilder. By looking at HtmlHeadBuilder.GetChildControlType we can tell that it only recognizes two different child types: HtmlTitle and HtmlLink. There is no recognition here for the <meta> element, moreover, there is not even a HtmlMeta control (as there are HtmlTitle and HtmlLink ones).
This means any <meta> elements that you may specify at design-time will be parsed as a single LiteralControl.
When it is time to render, HtmlHead rendering basically does the following (warning: very-simplistic-pseudo-code-follows):
- Render HtmlHead’s child controls (this will render the LiteralControl containing the <metadata> specified at design-time)
- Render HtmlTitle (or a blank <title></title> if none is found)
- Render Metadata items that were added programmatically
Remember our <meta> elements specified at design-time were parsed as a single LiteralControl and added to HtmlHead’s control collection. So they will be rendered before any other output of the HtmlHead control.
I’m hoping for this funny reordering to go away soon. I believe that modifying HtmlHeadBuilder to recognize childs of type HtmlMetadata (and adding such a control in the meantime) will make everyone (or at least me!) happy.
Any current page that has more than a <title> element, i.e.:
<head>
<title>Title One</title>
<title>Titlo Two</title>
</head>
Is violating the HTML401 spec which says that only one <title> element is allowed.
But spec compliance aside, nothing stops current ASP.NET pages to specify such markup. The end result will be that both elements will be rendered and browsers (FireBird/Fox, poor-old IE, etc) will only take into account the first <title> found.
So far so good.
Now, while porting your pages to Whidbey you need to add a runat=”server” attribute to the <head> element in order for some of the built-in functionally to work.
Which one would you expect to render as the title? “Title One” or “Title Two”?
You know that the ASP.NET Team is pushing hard for zero breaking changes, so you would expect “Title One” to render, just in case you have some really ugly javascript code that depends on the page’s title.
But… if you try this against the March04 preview the browser will render “Title Two”…
So far not so good now.
If you look at the rendered markup you’ll notice that only a single <title> element is being rendered now, where on earth did the other <title> element went?
The answer lies down in the HtmlHead.AddParsedSubObject method which is coded in a way that when it detects a child of type HtmlTitle it saves a reference to it using a private member variable. It doesn’t check if it has already assigned an HtmlTitle already so when the second HtmlTitle child is processed it just overwrites the first one.
When it comes down to rendering the control has saved only one HtmlHead, and it is the last one processed thus we get a different <title> than the one we should get when running the page in v1.x bits.
I believe that modifying the HtmlHead.AddParsedSubObject to only save the first HtmlTitle child found and just ignoring any following childs of the same type would be a more friendly approach. (Of course what I really would like is to throw an exception yelling “Hey Joe, you have specified more than one <title> element, go read the spec!” but that could be considered a really breaker :-) )