I recently had a requirement to modify some Html-based reports. These reports were built up in code using a StringBuilder, along with report content data. The plus-point is that it worked and delivered the desired reports. On the downside, the code was tedious and verbose. For example:
StringBuilder stringBuilder = new StringBuilder();
stringBuilder.Append("<TABLE id=\"Table2\" width=\"100%\">");
stringBuilder.Append("<TR style=\"page-break-inside : avoid\"><TD class=\"reportHeaderTitle\" >" + ResourceManager.GetString("ReportTitle", culture) + "</TD></TR>");
stringBuilder.Append("<TR><TD style=\"PADDING-LEFT: 5px; PADDING-BOTTOM:10px\" width=\"100%\">");
stringBuilder.Append("<TABLE id=\"Table2\" width=\"100%\">");
stringBuilder.Append("<TR style=\"page-break-inside : avoid\"><TD class='reportHeader' align=\"center\" width=\"50%\">" + ResourceManager.GetString("ReportSubTitle", culture) + "</TD>");
stringBuilder.Append("<TD class='reportHeader' align=\"center\" width=\"50%\">" + ResourceManager.GetString("ReportResults", culture) + "</TD></TR>");
...
I was staring at 1000s of lines of code like this. After a while it was all a blur.
My first impulse was to subclass the StringBuilder and build up some Html-specific methods. Unfortunately, the StringBuilder class is sealed. I also looked at the HtmlTextWriter class, a class primarily used when working with custom server controls. But, this seemed overkill for the purpose. I just needed a clean way to build-up an Html string in code.
I then turned to writing a set of Extensions Methods to provide this functionality.
#region Using Directives
using System.Text;
#endregion
namespace Common.Extensions
{
public static class StringBuilderExtensions
{
public static void BeginTable(this StringBuilder stringBuilder)
{
stringBuilder.Append("<table>");
}
public static void EndTable(this StringBuilder stringBuilder)
{
stringBuilder.Append("</table>");
}
public static void BeginRow(this StringBuilder stringBuilder)
{
stringBuilder.Append("<tr>");
}
...
}
}
In refactoring the code I first pulled all of the inline styles out and into style classes. Then I began migrating the existing code over to use the new extension methods. The refactored code looks something like this:
var stringBuilder = new StringBuilder();
stringBuilder.HorizontalRule();
stringBuilder.BeginH2();
stringBuilder.Append(ResourceManager.GetString("ReportTitle", _Culture));
stringBuilder.EndH2();
stringBuilder.BeginTable();
stringBuilder.BeginTHead();
stringBuilder.BeginRow();
stringBuilder.BeginCell("reportHeader");
stringBuilder.Append(ResourceManager.GetString("ReportSubTitle", _Culture));
stringBuilder.EndCell();
stringBuilder.BeginCell();
stringBuilder.Append(ResourceManager.GetString("ReportResults", _Culture));
stringBuilder.EndCell();
stringBuilder.EndRow();
stringBuilder.EndTHead();
...In it's current state, the extensions only supply the Html tags that were required, but could easily be expanded to support all of the commonly used tags. I personally find this refactored code much easier to read and maintain.
You can download the StringBuilderExtensions.zip
here.
I hope this may be of some use.