Using HtmlTextWriter to Create Controls that Output Valid Html
Denise Wynn
April 15, 2005
The HtmlTextWriter class allows you to decide how the html output of your user controls should render. This gives you a very precise level of control over the output. Instead of relying on the server to determine what the control output should be (based on browser) you can specify that based on whatever criteria you choose.
One of the issues I have with using some of the built in ASP.NET web server controls is the fact that they have a tendency to output code that doesn't validate. It doesn't matter what DTD (Document Type Definition) you are using, the web server control is going to output html based on browser detection and some odd mixture of various versions of html/xhtml. Another issue would be the fact that you have no control over some attributes and ASP.NET is going to add those attributes even if you didn't specify them.
A simple example of this is the image web server control. This control allows you to specify the id, image location, alternate text, and alignment. There are no options for height and width. You can add those attributes to the control and they will work though. You could also set these programmatically using the image class but I want to focus on the control for now.
If you add an image web server control to your page it might look something like this:
<asp:image runat="server" imageurl="banner.jpg"
alternatetext="Banner Image" />
You would think that this will output an img element with just the src and alt attributes. What you actually get is this:
<img src="banner.jpg" alt="Banner Image" border="0" />
Where did that border="0" come from? I didn't specify it and I wasn't expecting it. If you were using an xhtml-strict DTD then validation just went out the window as the border attribute is not allowed. The border attribute was deprecated in html 4.01 but the self closing end tag "/>" is xhtml, so if you are using any html DTD your page will not validate. Unfortunately you can't change this behavior; the self-closing end tag will be rendered in any browser. The only DTD's that will work with this output are xhtml-transitional and xhtml-frameset.
We want a control that is going to generate output that conforms to a specific DTD and we can use HtmlTextWriter to achieve this. HtmlTextWriter gives us an extremely granular level of influence over the html output that our control generates. To demonstrate we'll implement a simple image control with a dtd attribute that takes either html or xhtml as values and outputs the appropriate closing tag accordingly. This is the code for the control.
<%@ Control runat="server" language="c#" %>
<script runat="server" language="c#">
private string alt = null;
private string src = null;
private string dtd = "html";
public string AlternateText
{
get{ return alt;}
set{ alt = value;}
}
public string ImageUrl
{
get{ return src;}
set{ src = value;}
}
public string Dtd
{
get{ return dtd;}
set
{
//if the value isn't html or xhtml then we don't want it
if (value.ToLower() == "html" | value.ToLower() == "xhtml")
{
dtd = value.ToLower();
}
}
}
protected override void Render(HtmlTextWriter writer)
{
//this will output the start of the img element - <img
writer.WriteBeginTag("img");
//this will output the src and alt attributes
writer.WriteAttribute("src", src);
writer.WriteAttribute("alt", alt);
//this will output the end of the img element based on dtd
if (dtd == "xhtml")
{
//if it's xhtml we want a self closing end tag "/>"
writer.Write(HtmlTextWriter.SelfClosingTagEnd);
}
else
{
//if it's html we only want to output a right-angle bracket ">"
writer.Write(HtmlTextWriter.TagRightChar);
}
}
</script>
This control is very basic and will allow you to set the src and alt attributes for an image as well as specifying if you want html or xhtml output.
Now that we've got our control we can implement it in a page. I've written a test page to test the xhtml output.
<%@ Page runat="server" language="c#" %>
<%@ Register TagPrefix="nbs" TagName="image" Src="nbsimage.ascx" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html>
<head>
<title>Image web server control test</title>
</head>
<body>
<nbs:image runat="server" imageurl="banner.jpg"
alternatetext="Banner Image" dtd="xhtml" />
</body>
</html>
The output from the control looks like this:
<img src="banner.jpg" alt="Banner Image" />
Notice it is xhtml compliant and does not have the extraneous border="0" attribute and value. If we wanted to output an img element without the self closing end tag we would just change the dtd value to html or leave off the dtd attribute altogether since the default value is html. Doing so would output this code:
<img src="banner.jpg" alt="Banner Image">
You've just seen a very simple demonstration of the HtmlTextWriter class and how to use it to generate output that will validate. The control could easily be extended to include additional attributes or abilities rendered using HtmlTextWriter. This rich class provides the opportunity to create controls that output html exactly the way you want it so you aren't surprised by the server-side interpretation.
Formatting Html Output with HtmlTextWriter builds on the information in this article and demonstrates how to output html source that is formatted for readability.
