I recently wrote a web application and I wanted to create my own tag cloud. Since I was writing an MVC application I decided to use the HtmlHelper class. In case you are not familiar with it, here is a small description from MSDN:

The HtmlHelper class provides a set of helper methods whose purpose is to help you create HTML controls programmatically. All HtmlHelper methods generate plain HTML and return the result as a string.

Extensions to the HtmlHelper class are located in the System.Web.Mvc.Html namespace. These extensions add helper methods for creating forms, rendering HTML controls, rendering partial views, input validation, and more.

All helper methods and extensions are called using the Html property of the view, which is an instance of the HtmlHelper class. For example, to generate a check box in your form, you would call the Html.CheckBox method.

In order to store the data for my tag cloud I decided to use XML. Yes, I could have used a database for my tag cloud but I wanted this component to be independent enough where I could easily plop it into another web app without having to require a database. To make the process of loading and saving the data to XML easier I used the System.Data.DataSet class. Simply because the DataSet class already has methods for dealing with XML (ReadXml and WriteXml). The first time the tag cloud is rendered I load the XML file from disk into a DataSet which in turn, creates a single DataTable containing all of my "tag" data. Here is the code for creating the dataset, and reading and writing the XML:

   1:     private static DataSet CreateDataSet() {      
   2:        DataSet dataSet = new DataSet();
   3:        DataTable table = new DataTable( "TagCloud" );         
   4:        table.Columns.Add("key", typeof(string));
   5:        table.Columns.Add("value", typeof(int));
   6:        dataSet.Tables.Add(table);
   7:        return dataSet;      
   8:     }
   9:   
  10:      private static void SaveToXML() {
  11:          try {
  12:              DataSet dataSet = CreateDataSet();
  13:              var qry = from x in Cloud
  14:                           orderby
  15:                              x.Key,
  16:                              x.Value
  17:                           select x;
  18:              DataTable table = dataSet.Tables["TagCloud"];
  19:   
  20:              foreach (var item in Cloud.Take(CLOUD_SIZE)) {
  21:                  DataRow row = table.NewRow();
  22:                  row["key"] = item.Key;
  23:                  row["value"] = item.Value;
  24:                  table.Rows.Add(row);
  25:              }
  26:              dataSet.AcceptChanges();
  27:              dataSet.WriteXml(XMLFile, XmlWriteMode.WriteSchema);
  28:          }
  29:          catch {
  30:              //
  31:          }
  32:      }
  33:   
  34:     private static void LoadFromXML() {
  35:        if(System.IO.File.Exists(XMLFile) == false)
  36:           return;
  37:   
  38:          _cloud = new Dictionary<string, int>();
  39:        _cloud.Clear();
  40:   
  41:          DataSet dataSet = CreateDataSet();
  42:          dataSet.ReadXml(XMLFile, XmlReadMode.ReadSchema);
  43:        DataTable table = dataSet.Tables["TagCloud"];
  44:        foreach(DataRow row in table.Rows) {
  45:           _cloud.Add(row["key"].ToString(), (int)row["value"]);
  46:        }
  47:     }

To add a tag to the cloud you call the AddTag method. This just adds a row to the static variable used to store the tag information. In my case, I immediately flush the updates to the XML file but you could do occasional updates or rely on the Application_End method of the Global.asax file to persist the data to disk. Here is the code:

   1:      public static void AddTag(string tag) {
   2:          tag = tag.ToLower();
   3:   
   4:          if (Cloud.ContainsKey(tag) == false)
   5:              Cloud.Add(tag, 1);
   6:          else {
   7:              int value;
   8:              if (Cloud.TryGetValue(tag, out value) == true) {
   9:                  Cloud[tag] = value + 1;
  10:              }
  11:          }
  12:   
  13:          SaveToXML();
  14:      }
 

To render the HTML for the tag cloud I use the code below. This is simply an extension method which utilizes the HtmlHelper class. You will notice that I hardcoded the CSS class names. You could optionally pass these in as variables or explicitly set the style in the markup. Since you are rendering the HTML you can do whatever you want.

   1:      public static string TagCloud(this HtmlHelper htmlHelper, bool showFrequency ) {        
   2:   
   3:          StringBuilder sb = new StringBuilder();        
   4:          var qry = from x in Cloud                      
   5:                       orderby                        
   6:                          x.Key,
   7:                    x.Value
   8:                       select x;        
   9:          
  10:          sb.Append("<ul id='tagCloud'>");
  11:   
  12:          var results = qry.Take(CLOUD_SIZE);
  13:          
  14:          if (results.Count() == 0) return String.Empty;
  15:   
  16:          double largest = results.Max(x => x.Value);                
  17:          
  18:          foreach (var item in qry.Take(CLOUD_SIZE)) {
  19:              double val = Convert.ToDouble(item.Value);
  20:              sb.Append("<li>");
  21:              if (val.Between(0.0, largest * .25))
  22:                  sb.Append("<a class='small' ");
  23:              else if (val.Between(largest * .25, largest * .50))
  24:                  sb.Append("<a class='medium' ");
  25:              else if (val.Between(largest * .50, largest * .75))
  26:                  sb.Append("<a class='large' ");
  27:              else
  28:                  sb.Append("<a class='xlarge' ");
  29:   
  30:              sb.Append(" title='" + item.Value + " hit(s)' href='/Search/" + item.Key.UrlEncode() + "'>" + item.Key + "</a></li>");
  31:              sb.Append( "<li><a class='freq'>(" + item.Value + ")</a></li>");            
  32:          }
  33:          sb.Append("</ul>");
  34:   
  35:          return sb.ToString();
  36:      }

Finally, on the page I want to display the tag cloud I need to add this line of code:

<%= Html.TagCloud() %>

Here is the result:

 

References:

ASP.NET MVC: Using the MVC UI Helpers
ASP.NET Application variables or Static Members?
.NET Static Variables : Better than Application!