[Source: http://geekswithblogs.net/EltonStoneman]

Keeping up the fluent work, I’ve put together a fluent interface which wraps the framework HtmlTextWriter. For ASP.NET MVC, this makes generating HTML in extension methods to HtmlHelper safer than string.Format() and more readable than HtmlTextWriter:

public static string Image(this HtmlHelper helper, string imageRelativeUrl, string altText)

{

return FluentHtmlTextWriter.Begin()

.WriteTag(HtmlTextWriterTag.Img)

.WithAttribute(HtmlTextWriterAttribute.Src, GetImageUrl(imageRelativeUrl))

.WithAttribute(HtmlTextWriterAttribute.Alt, altText)

.End();

}

The equivalent using HtmlTextWriter is:

public static string Image(this HtmlHelper helper, string imageRelativeUrl, string altText)

{

StringBuilder htmlBuilder = new StringBuilder();

HtmlTextWriter writer = new HtmlTextWriter(new StringWriter(htmlBuilder));

writer.AddAttribute(HtmlTextWriterAttribute.Src, GetImageUrl(imageRelativeUrl));

writer.AddAttribute(HtmlTextWriterAttribute.Alt, altText);

writer.RenderBeginTag(HtmlTextWriterTag.Img);

writer.RenderEndTag();

writer.Flush();

return htmlBuilder.ToString();

}

Unlike the framework writer, you’re not constrained to specify attributes in any particular order, and tags which aren’t nested can be written with a single WriteTag(), rather than BeginTag() and EndTag() calls. The writer copes with multi-level tag hierarchies – this sample builds a Superfish CSS menu:

FluentHtmlTextWriter writer = FluentHtmlTextWriter.Begin();

writer.BeginTag(HtmlTextWriterTag.Ul)

.WithAttribute(HtmlTextWriterAttribute.Id, “menu.Name”)

.WithAttribute(HtmlTextWriterAttribute.Class, “sf-menu sf-vertical”);

.BeginTag(HtmlTextWriterTag.Li)

.BeginTag(HtmlTextWriterTag.A)

.WithAttribute(HtmlTextWriterAttribute.Class, “sf-with-ul”)

.WithAttribute(HtmlTextWriterAttribute.Href, “#”)

.WithValue(“Link 1”)

.WriteTag(HtmlTextWriterTag.Span)

.WithAttribute(HtmlTextWriterAttribute.Class, “sf-sub-indicator”)

.WithValue(“»”)

.EndTag()

.EndTag()

.EndTag();

string html = writer.End();

Assert.AreEqual(“<ul id=\”menu.Name\” class=\”sf-menu sf-vertical\”>\r\n\t<li><a class=\”sf-with-ul\” href=\”#\”>Link 1<span class=\”sf-sub-indicator\”>»</span></a></li>\r\n</ul>”,

html);

The HtmlTextWriter equivalent is unthinkable.

Patrik H%u00e4gne has an alternative fluent HtmlTextWriter implementation, which is nicely put together, but I wanted slightly different functionality. Firstly I wanted to get the HTML string from the writer directly, without needing to instantiate a StringBuilder and StringWriter. Secondly I wanted minimal new code – Patrik uses a separate class to manage writing attributes, and has specific functions for known tag types. Thirdly, I didn’t really like Patrik’s syntax, with the need to specify the tag type when you write an end tag – and when tags aren’t nested, I wanted to write them in a single unit:

string html = FluentHtmlTextWriter.Begin()

.WriteTag(HtmlTextWriterTag.Span)

.WithAttribute(HtmlTextWriterAttribute.Id, “id_span”)

.WithValue(“contents_span”)

.End();

Assert.AreEqual(“<span id=\”id_span\”>contents_span</span>”, html);

My version is on MSDN Code Gallery here: FluentHtmlTextWriter. It works by building up a list of actions when you start writing a tag, and flushing them in the correct order to an internal HtmlTextWriter when you start writing the next tag. When you call End() it flushes the internal writer and outputs its contents. An alternative constructor lets you write directly to an output stream, in which case you can Flush() the writer and don’t need to call End().

The current implementation only deals with basic tag, attribute and style functionality, and doesn’t include optional HTML encoding overloads. It’s only 75 lines of code, and extending it should be trivial.

There is a negligible performance hit in using FluentHtmlTextWriter – running the image tag generation code above 20,000 times on my dev machine, the fluent version takes between 0.01and 0.02 seconds longer than the framework version (on average 0.07 seconds compared to 0.05).