I have a belief that markup should remain in mark-up and not in the code behind.
I’ve come to a situation where I think it is acceptable to build the HTML in the code behind. I’d like to have some consensus as to what the best practices are or should be.
When is it acceptable to build html in the code behind? What is the best method to create this html? (example: Strings, StringBuilder, HTMLWriter, etc)
5
Is using something like Razor not applicable here? Because if you’re doing a lot of html generation using a view engine can make it a lot easier. It was also built to be used outside of ASP.NET.
However sometimes that’s not what you need. Have you considered using the TagBuilder class which is part of .net (mvc)? There is also the HtmlWriter in System.Web.UI (for web forms). I would recommend one of these if you are making Controls
or Html Helpers
.
3
I would use the Html Agility Pack to assemble HTML and then write it out to a text file.
A lot of man-hours went into making the Html Agility Pack robust and HTML-compliant HTML-friendly.
I think it even includes a sample application that generates HTML.
From the home page:
Sample applications:
Page fixing or generation. You can fix a page the way you want, modify the DOM, add nodes, copy nodes, well… you name it.
I would use htmltags to create HTML.
Example:
var tag = new HtmlTag("span")
.Text("Hello & Goodbye")
.AddClass("important")
.Attr("title", "Greetings")
And then CSQuery if I want to parse HTML
Example:
dom.Select("div > span")
.Eq(1)
.Text("Change the text content of the 2nd span child of each div");
There are, of course, libraries out there, such as HTML Agility Pack that can assist you in these endeavors.
If you realy don’t want to use an existing library, and want simple, down-and-dirty code, I like the idea of abstracting out some of the behaviors like a previous answer stated. I also like the idea of using an underlying StringBuilder, as opposed to a string for a couple reasons:
- Strings are less efficient than string builder
- StringBuilder is an indexable data structure,
If I don’t need a massively engineered HTML engine, I’d build a simple, intuitive interface
AddLineBreak();
AddSimpleTag(string tagName);
AddSimpleTagAt(string tagName, string content, int index);
Output();
3
FLAME ON!
var html = "";
html += "<table class='colorful'>";
foreach(var item in collection) {
html += "<tr>";
html += "<td class='boldCell'>" + item.PropWhatever + "</td>";
// more cells here as needed
html += "</tr>";
}
html += "</table>";
placeholder1.InnerHtml = html;
I will prob get downvoted for this, but as a former designer who had to tweak HTML in code before I really knew much about .NET, the above code was way easier to understand than the methods that abstract HTML creation. If you think a designer might ever have to tweak your HTML, use simple strings like this.
Something I see a lot of devs miss when they write HTML in code is that in HTML, single or double quotes are allowed for attributes. So instead of escaping all the quotes in code (which looks wanky as hell to the non-initiated), just use single quotes for the html quotes inside your strings.
FINE. All you string concatenating haters are crampin’ my rep. Here’s the ‘proper’ way to do this without string concatenation, but I stand by my opinion that any normal page with normal tables won’t present any performance problems outside of some ridiculous Google-like scale:
var sb = new System.Text.StringBuilder();
sb.Append("<table class='colorful'>");
foreach (var item in collection)
{
sb.Append("<tr>");
sb.Append("<td class='boldCell'>" + item.PropWhatever + "</td>");
// more cells here as needed
sb.Append("</tr>");
}
sb.Append("</table>");
placeholder1.InnerHtml = sb.ToString();
10
If you do end up using just strings, don’t forget to escape all the HTML reserved characters in your output data.
& &
> >
< <
" "
' '
I recommend using an HTML-aware class or library instead of working directly with strings, though. HTMLWriter looks like a pretty good start.
1
Nearly two years after the original post – here is a solution that has worked well for me. In the target document I place the following:
<table>
<%:theHtmlTableMomToldYouAbout() %> //# Where I want my rows of table data to go
</table>
the function being called looks like this:
public HtmlString theHtmlTableMomToldYouAbout()
{
string content = "";
HtmlString theEnvelopePlease = null;
for (int i = 0; i < 5; i++)
{
content = content + "<tr><td>The Number Is: " + i + "</td></tr>";
}
theEnvelopePlease = new HtmlString(content);
return theEnvelopePlease;
}
And the resulting output in the browser is as expected:
The Number Is: 0
The Number Is: 1
The Number Is: 2
The Number Is: 3
The Number Is: 4
When I go to view source I find the following:
<table>
<tr><td>The Number Is: 0</td></tr>
<tr><td>The Number Is: 1</td></tr>
<tr><td>The Number Is: 2</td></tr>
<tr><td>The Number Is: 3</td></tr>
<tr><td>The Number Is: 4</td></tr>
</table>
1