Melbourne Web Solutions|Design - Providing Web Design and Development for Brevard County, Florida
Contact Search Archive Portfolio Services

Exporting Data Tables To Microsoft Excel from ASP.NET Pages

by Nicole Thursday, July 22, 2010 8:17 AM

Exporting Data Tables To Microsoft Excel from ASP.NET Pages

The Microsoft Excel export method involving a gridview control is fairly well known. Take a gridview that does not have paging and sorting enabled, pass it into the method below, and up comes an Excel file:

  1.     /// <summary>
  2.     /// This method takes in the specified gridview and creates a Microsoft Excel sheet from it.
  3.     /// Only use this method for a gridview in which paging or sorting is not in effect.
  4.     /// </summary>
  5.     /// <param name="gv"></param>
  6.     /// <param name="filename"></param>
  7.     public static void ExportToExcel(GridView gv, string filename)
  8.     {
  9.         HttpContext cont = HttpContext.Current;
  10.         cont.Response.Clear();
  11.  
  12.         string header = "attachment; filename=" + filename + ".xls";
  13.         cont.Response.AppendHeader("content-disposition", header);
  14.  
  15.         cont.Response.ContentType = "application/vnd.ms-excel";
  16.  
  17.         StringWriter sw = new StringWriter();
  18.         Html32TextWriter htw =new Html32TextWriter(sw);
  19.  
  20.         HtmlForm form = new HtmlForm();
  21.         gv.Parent.Controls.Add(form);
  22.  
  23.         // Add the new grid view to the new form
  24.         form.Controls.Add(gv);
  25.  
  26.         //Render the new form to the HTML text writer
  27.         form.RenderControl(htw);
  28.  
  29.         cont.Response.Write(sw.ToString());
  30.         cont.Response.End();
  31.         cont.Response.Clear();
  32.  
  33.         // Clean up
  34.         form.Dispose();
  35.         gv.Dispose();
  36.         htw.Dispose();
  37.         sw.Dispose();
  38.     }

In reality, all Microsoft Excel does is read the rendered HTML of the gridview control passed into the HTTP response output stream from the method. But gridview HTML is notoriously inefficient, with unnecessary nested tables. Also, if you're not creating the gridview to display on the page, you have to programmatically create the gridview, add the columns (unless you use auto generate columns, but have no control over the column names displayed), bind the gridview, and pass it into the method. I have done this countless times on reports pages and always thought how great it would just to pass in a data table instead of the hassle of a programmatically generated gridview.

So, I did what a developer does when he/she gets frustrated - found a work around! In this case, it was writing a simple method that took in a data table and then appends the necessary HTML to create a table out of its rows. It's the same concept as the method above but with less overhead and cleaner HTML.

I thought I'd share my method. Note that this only works with Microsoft Excel 2003. It seems that Excel 2007 got rid of ability to read HTML tables. Work around? Try EPPLus using Office Open XML.

  1.     public static void ExportToExcel(DataTable dt, string fileName)
  2.     {
  3.         if (dt != null)
  4.         {
  5.             HttpContext cont = HttpContext.Current;
  6.             cont.Response.Clear();
  7.  
  8.             string header = "attachment; filename=" + fileName + ".xls";
  9.             cont.Response.AppendHeader("content-disposition", header);
  10.             cont.Response.ContentType = "application/vnd.ms-excel";
  11.  
  12.             StringBuilder sb = new StringBuilder();
  13.  
  14.             // Render out an HTML table to pass into Excel
  15.             sb.Append("<table cellpadding=2 cellspacing=2>");
  16.  
  17.             // Get all column names
  18.             sb.Append("<tr>");
  19.  
  20.             foreach (DataColumn dc in dt.Columns)
  21.             {
  22.                   sb.Append("<td>");
  23.  
  24.                   sb.Append("<b>" + dc.ColumnName.Replace("_", " ") + "</b>");
  25.  
  26.                   sb.Append("</td>");
  27.             }
  28.  
  29.             sb.Append("</tr>");
  30.  
  31.             // Handle table rows and cells
  32.             for (int i = 0; i < dt.Rows.Count; i++)
  33.             {
  34.                 sb.Append("<tr>");
  35.  
  36.                 foreach (DataColumn dc in dt.Columns)
  37.                 {
  38.                     sb.Append("<td>");
  39.  
  40.                     sb.Append(dt.Rows[i][dc].ToString());
  41.  
  42.                     sb.Append("</td>");
  43.                 }
  44.  
  45.                 sb.Append("</tr>");    
  46.             }
  47.  
  48.             // Close the table tag
  49.             sb.Append("</table>");
  50.  
  51.             dt.Dispose();
  52.  
  53.             // Pass the table HTML string into the response output stream to be passed to Excel
  54.             cont.Response.Write(sb.ToString());
  55.             cont.Response.End();
  56.             cont.Response.Clear();
  57.         }
  58.         else
  59.         {
  60.             throw new Exception("The data table cannot be null.");
  61.         }
  62.     }