Written By: Christopher Brandsma,
chris.brandsma@gmail.com
Tree Top Technologies (www.treetoptech.com)
Date: June 2, 2005
Technologies: .NET Framework 1.1, ASP.NET, ADO.NET, C#,
Excel
I am going to start by labeling the two methods: the Traditional way and the Extreme way. There is nothing extreme about the code involved in the Extreme way, but it does help highlight one of the main differences between the two methods.
But first an explanation of the Traditional way. If you do any Google search on ASP.NET Export to Excel, you will see this method. The formula works like this: take a standard ASP.NET DataGrid, do the standard data binding, grab the output, and stream it to Excel. The best part is, using this method, the data is formatted in Excel just the same as it is in the ASP.NET DataGrid. If you do any special text formatting in the DataGrid (using the ItemDataBound event) it will be formatted that way in both the DataGrid and in Excel.
The basic code for this looks like this (note: I’m using the Oracle data client here, don’t worry, it works for all the different data clients):
string sConn = ConfigurationSettings.AppSettings["OracleConnectionString"];
OracleConnection oConn = new OracleConnection(sConn);
string sHTML = "";
using(OracleCommand oCmd = new OracleCommand(sql, oConn))
{
oConn.Open();
OracleDataReader oReader = oCmd.ExecuteReader(CommandBehavior.SingleResult);
// setup and load the grid,
System.Web.UI.WebControls.DataGrid oGrid = new System.Web.UI.WebControls.DataGrid();
oGrid.HeaderStyle.BackColor = System.Drawing.Color.Silver;
oGrid.HeaderStyle.ForeColor = System.Drawing.Color.Black;
// Bind the data to the grid
oGrid.DataSource = oReader; oGrid.DataBind();
// grab the data grid html text
System.IO.StringWriter oStringWriter = new System.IO.StringWriter();
System.Web.UI.HtmlTextWriter oHTMLWriter = new System.Web.UI.HtmlTextWriter(oStringWriter);
oGrid.RenderControl(oHTMLWriter);
sHTML = oStringWriter.ToString();
oHTMLWriter.Close();
oStringWriter.Close();
}
// send the data to Excel on the client’s machine
Response.Clear();
Response.ContentType = "application/vnd.ms-excel";
Response.Charset = "";
Response.Write(sHtml);
Response.End(); But there is one little side effect: when you use this method, all of the data in the query has to be downloaded, and loaded into the ASP.NET DataGrid before it can be sent to Excel on the Client’s machine. If you are not pulling large amounts of data and the connection between the database and the web server is fast, this may not be an issue. Otherwise there are two significant issues:
Enter the Extreme Way
I call this the Extreme Way because it is specifically suited for dealing with exporting extreme amounts of data (well, extreme amounts of data for Excel might not be that much – say 10,000 rows, but you get the idea).
The idea here is to forgo the tradition use of using the ASP.NET components just because they exist. This is also breaking a Microsoft ASP.NET best practice, but best practices are only best practices when they work. If a best practice causes IIS to run out of memory, it is no longer a best practice in my book.
So, in this method, we are going to create the HTML table by hand, streaming it to the client as we go. And not using StringBuilder either! To use StringBuilder would be to build the entire file on the server again, we don’t want that.
Response.Write("<HTML>");
Response.Write("<HEAD><STYLE>.HDR { background-color:bisque;font-weight:bold }</STYLE></HEAD>");
Response.Write("<BODY><TABLE>");
string sConn = ConfigurationSettings.AppSettings["OracleConnectionString"];
using(OracleConnection oConn = new OracleConnection(sConn))
{
oConn.Open();
string sCmd = txtSQL.Text;
OracleCommand oCmd = new OracleCommand(sCmd, oConn);
using(OracleDataReader oReader = oCmd.ExecuteReader(CommandBehavior.SequentialAccess))
{
for (int i=0; i<oReader.FieldCount; i++)
{
string sColName = HttpUtility.HtmlEncode(oReader.GetName(i));
Response.Write("<TD CLASS=\"HDR\">");
Response.Write( sColName );
Response.Write( "</TD>\n" );
}
int iRowCount = 0;
while (oReader.Read())
{
iRowCount++;
if ( iRowCount < EXCEL_MAX_ROWS)
{
Response.Write("<TR>");
for(int i=0; i<oReader.FieldCount; i++)
{
string sValue = HttpUtility.HtmlEncode(oReader.GetValue(i).ToString());
if (sValue.Length > EXCEL_MAX_CELL_SIZE)
sValue = sValue.Remove(EXCEL_MAX_CELL_SIZE-1, sValue.Length);
sValue = FormatForExcel(sValue);
Response.Write("<TD>");
Response.Write(sValue);
Response.Write("</TD>");
}
Response.Write("</TR>");
// send the data in the Response object
to the client
Response.Flush();
}
}
}
}
Response.Write("</TABLE></BODY></HTML>");
Response.End();
There is one other piece to this puzzle that needs to be exposed, and that is this code:
/// <summary>
/// Formats the
text so that Excel doesn't barf when rendering.
/// </summary>
/// <param name="text"></param>
///
<returns></returns>
public static
string FormatForExcel(string text)
{
string sReturn = System.Web.HttpUtility.HtmlEncode(text);
while((sReturn.Length > 0) && (( sReturn[0] == '-') || (sReturn[0] == '=')) ||
(sReturn[0] == '+'))
{
sReturn
= sReturn.Remove(0,1);
}
return sReturn;
}
This code removes any special characters that would make Excel thing that the output is a formula instead of data. If you don’t do this, you will be inundated with “Cell data too large” messages from Excel.
So how does this help? First off, within seconds, the user is presented with the dialog to either Save, Open, or Cancel (see dialog below).

If the user clicks Save, they will see this dialog:
Now compare what is happening on the web server between the two methods.
Note: use the Task Manager or PerfMon to monitor your memory usage. Other sources for .NET performance monitoring can be found at http://msdn.microsoft.com/perf and at Rico Mariani's Performance Tidbits bog http://blogs.msdn.com/ricom.
So is this really any better for the user?
Don’t forget the user. So the server likes this better, what about the end user?
Is this way better? Yes.
Is this way faster? Not really.
The difference is in perception. Using the traditional method, the user would receive no feedback from the system to tell them that: “Yes, I, the server you have contacted, have received your request, and I am working on it. Please return back for the answer in 5 million years.”
Using the Extreme way, the user quickly sees that things are happening: data is moving, a file is being created on the spot, spontaneous joy commences! Or something like that. The key is feedback. Users hate feeling helpless to the computer. Giving them some feedback as to what is happening lets the user feel involved and part of the process. That way they are more likely to forgive your bad coding on insufficient web servers.