XHTML Compliance in ASP.NET 2.0
Recently I’ve written a large amount of CompositeControls (WebControls) at work for a website I’ve been working on. This website is intended to be used by government agencies and other offices that have a requirement for all pages and output to be W3C and WCAG compliant, which is pretty simple to do thanks to the wonderful XHTML compliance checker that is built in to the page “source” view.
So after looking at all my pages and removing the surrounding paragraph tags from my tables (which I had blindly grown so fond of) I noticed that even though the pages were fine in the source view, the output itself was not compliant and showed some strange behaviour. This error is identified on the W3C Markup Validation Service by “document type does not allow element “table” here; missing one of “object”, “applet”, “map”, “iframe”, “button”, “ins”, “del” start-tag.“
This is caused by the way ASP.NET handles composite and web controls, assuming all controls are intended to be subject to flow layout. When a control is rendered that has some theme or style property set in the designer, it surrounds the control in a <span> tag in order to apply the style attribute. If this control contains a Panel, Table, or any other block-element control, the validator fails due to the rule that flow elements cannot contain block elements. This is fair enough, the html shouldn’t render in this way, but the next task is forcing it to render in the correct way.
After a little searching and poking around with Reflector, I wondered why the Panel control worked fine (which inherits from WebControl) places itself in a <div> tag. The simple answer is that the constructor of the Panel control uses an internal base call on its constructor:
public Panel(): base(HtmlTextWriterTag.Div)
{
}
When the WebControl is created normally, it defaults to the HtmlTextWriterTag.Span tag, and since this is an internal constructor, it is impossible to call this on creation of your own controls.
However, there is a solution to this. WebControl defines a property called TagKey and TagName. These properties expose (as read-only) the tag that has been set internally by the WebControl class. Every class that inherits the WebControl class exposes these methods – and therefore has the means to override these methods!
To force your control to display itself in a <div> tag, place the following code within your control:
[ToolboxData("<{0}:MyControl runat=server></{0}:MyControl>")]
public class MyControl : CompositeControl, INamingContainer
{
...
protected override HtmlTextWriterTag TagKey
{
get { return HtmlTextWriterTag.Div; }
}
protected override string TagName
{
get { return HtmlTextWriterTag.Div.ToString(); }
}
...
}
Luckily the WebControl accesses these properties instead of referring internally, and so it writes the tags that are returned by these properties.

Leave a Reply