Question

I'm trying to programmatically send an email of all of the dll files and their versions in a directory, recursively. I'd like to send the email as HTML output, using a table. Is there a good object-oriented way of doing this? I'd hate to write all of the tags by hand.

Something like:

private string getHTMLString()
{
    DirectoryInfo di = new DirectoryInfo("some directory");
    FileInfo[] files = di.GetFiles("*.dll", SearchOption.AllDirectories);
    foreach (FileInfo file in files)
    {
        Assembly assembly = Assembly.LoadFile(file.FullName);
        string version = assembly.GetName().Version.ToString();
    }
 }
Was it helpful?

Solution

Something like this?

private string getHTMLString()
{
    DirectoryInfo di = new DirectoryInfo("some directory");
    FileInfo[] files = di.GetFiles("*.dll", SearchOption.AllDirectories);
    StringBuilder sb = new StringBuilder();
    sb.Append("<table>");
    foreach (FileInfo file in files)
    {
        Assembly assembly = Assembly.LoadFile(file.FullName);
        string version = assembly.GetName().Version.ToString();
        sb.AppendFormat("<tr><td>{0}</td><td>{1}</td></tr>", file.FullName, version);
    }
    sb.Append("</table>");
    return sb.ToString();

 }

Not really "object oriented" but I would argue the most logical.

DISCLAIMER: Compiled by hand

OTHER TIPS

You can do it OO by instantiating a System.Web.UI.WebControls.Table, adding TableRows and TableCells and then calling Table.RenderControl into an HtmlTextWriter, but to be fair: That would suck :)

        var tbl = new System.Web.UI.WebControls.Table();

        DirectoryInfo di = new DirectoryInfo("some directory");
        FileInfo[] files = di.GetFiles("*.dll", SearchOption.AllDirectories);
        foreach (FileInfo file in files)
        {
            Assembly assembly = Assembly.LoadFile(file.FullName);
            string version = assembly.GetName().Version.ToString();

            var tr = new System.Web.UI.WebControls.TableRow();
            var tc = new System.Web.UI.WebControls.TableCell();
            tc.Text = HttpUtility.HtmlEncode(version);
            tr.Cells.Add(tc);
            tbl.Rows.Add(tr);
        }

        using (var ts = new StringWriter())
        using (var html = new System.Web.UI.HtmlTextWriter(ts))
        {
            // Not entirely sure about this part
            tbl.RenderControl(html);
            html.Flush();
            string htmlString = ts.ToString();
        }

You can actually use the HtmlTextWriter and use the HtmlTextWriterTag enum to create the tags, without actually having to hand write the "<" and ">".

Example:

StringBuilder sb = new StringBuilder();

using (HtmlTextWriter w = new HtmlTextWriter(new StringWriter(sb)))
{
      w.RenderBeginTag(HtmlTextWriterTag.P);

      w.AddStyleAttribute(HtmlTextWriterStyle.Color, "red");

      w.RenderBeginTag(HtmlTextWriterTag.Span);

      w.Write("This is some text");

      w.RenderEndTag();

      w.RenderEndTag();
 }

 string html = sb.ToString();

It doesn't automatically create the HTML for you, but it does help you write HTML in a "more OO" way and it will help you (not ensure) write valid HTML (all tags have closing tags, etc).

It might be overkill, but you can use LINQ to XML to generate your HTML string... Here's your code, using LINQ and XElement to generate a simple table.

The only thing you need to be careful of is empty tags that are not valid as self-closing tags in HTML. For example, an empty TD: new XElement("td") will render as <td/> which is not valid HTML. You can fix this by inserting an empty string as content: new XElement("td", String.Empty) - this will output <td></td>.

private string GetHtmlString()
{
    DirectoryInfo di = new DirectoryInfo("some directory");
    FileInfo[] files = di.GetFiles("*.dll", SearchOption.AllDirectories);

    var container = new XElement("table",
        from file in files
        let assembly = Assembly.LoadFile(file.FullName)
        select new XElement("tr", 
            new XElement("td", file.FullName),
            new XElement("td", assembly.GetName().Version.ToString())
        )
    );

    return container.ToString();
 }

Tags are tags. You'll have to write them.

You can use an HtmlTextWriter to do the actual writing, but there's no magical way to avoid that.

What you are doing seems simple enough to simply do it by hand with a string buffer. If this were more complicated I'd suggest you use a template engine such as StringTemplate.

You can use the XmlWriter to do this in a more OO-fashion:

StringBuilder sb = new StringBuilder();
XmlWriter xmlWri = XmlWriter.Create(sb);
xmlWri.WriteStartElement("html");
{
    xmlWri.WriteStartElement("body");
    {
        xmlWri.WriteAttributeString("bgcolor", "black");

        // More html stuff
    }
    xmlWri.WriteEndElement(); // body
}
xmlWri.WriteEndElement(); // html
xmlWri.Flush();
xmlWri.Close();
string html = sb.ToString();

Edit: It does get rather cumbersome to do this, and in the future if you want to change the HTML content you'll have to do it by code. A better way is to read in a pre-formatted HTML document with place-holders that map to the columns in the table, so all you'd need is a way to loop through all the columns and do a find/replace against the place-holders in the HTML document.

I'm currently writing a library that tackles that problem exactly. It allows you to construct your HTML with collection initializers, so it can be pretty concise. It also supports CSS styling, element attributes as optional parameters, etc. It's LGPL'd, so you can use it anywhere.

Your code will look like:

private string getHTMLString()
{
    DirectoryInfo di = new DirectoryInfo("some directory");
    FileInfo[] files = di.GetFiles("*.dll", SearchOption.AllDirectories);

    var table = new Table();

    foreach (FileInfo file in files)
    {
        Assembly assembly = Assembly.LoadFile(file.FullName);
        string version = assembly.GetName().Version.ToString();

        table.Add(new Tr { new Td { file.FullName }, new Td { version } });
    }

    return table.Render();
}

HTML++ on SourceForge.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top