2

I have the following code, the datatable already has the data and I want to export it to excel. However I get the following warning, I tried xlsx and it doesnt work. I also tried csv, and the data does not open into columns as I need.

public static void ExportDatatabletoExcel(DataTable dt, List<string> columnNames)
        {
            try
            {
                const string attachment = "attachment; filename=elreport.xls";
                HttpContext.Current.Response.ClearContent();
                HttpContext.Current.Response.AddHeader("content-disposition", attachment);
                HttpContext.Current.Response.ContentType = "application/vnd.ms-excel";
                string tab = "";
                foreach (DataColumn dc in dt.Columns)
                {
                    if (!columnNames.Contains(dc.ColumnName)) continue;
                    HttpContext.Current.Response.Write(tab + dc.ColumnName);
                    tab = "\t";
                }
                HttpContext.Current.Response.Write("\n");
                int i;
                foreach (DataRow dr in dt.Rows)
                {
                    tab = "";
                    for (i = 0; i < dt.Columns.Count; i++)
                    {
                        if(!columnNames.Contains(dt.Columns[i].ColumnName)) continue;
                        HttpContext.Current.Response.Write(tab + dr[i].ToString());
                        tab = "\t";
                    }


                    HttpContext.Current.Response.Write("\n");
                }
                HttpContext.Current.Response.End();
            }
            catch (Exception ex)
            {
                string errorMessage = String.Format("ExportToExcelError: {0}", ex.Message);
                LoggingService.LogError(LoggingCategory.General, ex, errorMessage);
                throw;
            }
        }

Error is:

Luis Valencia
  • 32,619
  • 93
  • 286
  • 506

2 Answers2

3

This answer from How to suppress the file corrupt warning at Excel download? addresses some of the problem. I recommend checking out some of the other answers as well.

The alert is a new security feature in Excel 2007 called Extension Hardening, which ensures that the file content being opened matches the extension type specified in the shell command that is attempting to open the file.

...

This issue is still being investigated, but a fix is not likely until Office 14 given the nature of the complexity of the code, and the fact that Excel does not want to lower the security measure to workaround IE open behaviors without a full understanding of the consequences for other browser users.

Also, this comment might help.

I think that only applies if you're using CSV and save as XLS. However, if you construct a real excel file, then it should be fine. CF9 cfspreadsheet will be your friend. :) – Henry Jun 25 '09 at 23:53

Other sources to check:

Community
  • 1
  • 1
JSuar
  • 21,056
  • 4
  • 39
  • 83
3

There are two sure ways to remove the warning.

  1. Build a valid .xlsx file using the OpenXML API or EPPlus API (EPPlus is easier and actually supports OleDB imports)

  2. Build the file as .csv with .csv extension, but leave the content-type as Excel so that it opens with Excel. However, the way you are building the file you may have issues with Excel reading the content correctly, which needs to be addressed:

Excel can only read CSV if it is formatted in certain ways. Also the encoding has to be windows 1252 assuming you are using Excel for windows, or it won't handle foreign chars. Also leading zeros from zip codes etc. need to be dealt with specially for Excel.

  public static class CSVExportUtility
    {
    /// <summary>
        /// Open a datatable in Excel
        /// </summary>
        /// <param name="dt"></param>
        /// <param name="fileName"></param>
        public static void OpenAsCSV(DataTable dt, string fileName)
        {
            CSVExportUtility.OpenAsCSV(DataTableToCSV(dt), fileName); // now open the file
        }   // OpenAsCSV
    /// <summary>
        /// open the content in the browser as a CSV
        /// </summary>
        /// <param name="sbCSVFileData"></param>
        /// <param name="filename"></param>
        public static void OpenAsCSV(StringBuilder sbCSVFileData, string fileName)
        {
            if (HttpContext.Current == null || HttpContext.Current.Response == null)
                return;

            HttpContext.Current.Response.Clear();
            HttpContext.Current.Response.AddHeader(
                "content-disposition", string.Format("attachment; filename={0}", fileName));
            HttpContext.Current.Response.ContentType = "application/ms-excel";

            // This is a little tricky.  Would like to use utf-8 or unicode... but Excel on Windows uses 1252 by default so we need to keep the same so most users can read the file.
            // At some point, we may need to actually convert our text from whatever .NET uses to 1252, but at the moment they seem similar enough that it is okay
            HttpContext.Current.Response.ContentEncoding = Encoding.GetEncoding(1252);

            //  render the htmlwriter into the response
            HttpContext.Current.Response.Write(sbCSVFileData.ToString());
            HttpContext.Current.Response.End();
        }

static StringBuilder DataTableToCSV(DataTable dt)
        {
            StringBuilder sb = new StringBuilder();
            foreach (DataColumn dc in dt.Columns)
            {
                if (dc == dt.Columns[dt.Columns.Count - 1])
                    CSVExportUtility.AddFieldForCSV(dc.ColumnName, sb, false, true);
                else
                    CSVExportUtility.AddFieldForCSV(dc.ColumnName, sb, true, false);
            }
            foreach (DataRow dr in dt.Rows)
            {
                foreach (DataColumn dc in dt.Columns)
                {
                    if (dc == dt.Columns[dt.Columns.Count - 1])
                        CSVExportUtility.AddFieldForCSV(FormatDataValue(dr[dc.ColumnName]), sb, false, true);
                    else
                        CSVExportUtility.AddFieldForCSV(FormatDataValue(dr[dc.ColumnName]), sb, true, false);
                }
            }
            return sb;
        }

  static string FormatDataValue(object dv)
        {
            if (dv == null)
                return null;
            if (dv is DateTime)
                return ((DateTime)dv).ToShortDateString();
            else
                return dv.ToString();
        }

        /// <summary>
        /// export text to a csv
        /// </summary>
        /// <param name="text"></param>
        /// <param name="sbCSV"></param>
        /// <param name="appendTrailingComma"></param>
        /// <param name="endOfRow"></param>
        public static void AddFieldForCSV(string text, StringBuilder sbCSV, bool appendTrailingComma, bool endOfRow)
        {
            // shouldn't start or end with whitespace, escape quotes
            if (text != null)
                text = text.Trim().Replace("\"", "\"\"");

            // quote field
            int testInt;
            if (text != null && text.Trim().Length > 1 && text.Trim()[0] == '0' && int.TryParse(text.Trim(), out testInt))
            {   // if text is numeric and starts with '0' tell excel to treat as string and not strip the zero. This ONLY works if it's numeric!  Otherwise it fails, example ="a,b" will use 2 cells
                text = "=\"" + text.Trim() + "\"";
            }
            else
            {
                text = "\"" + text + "\"";
            }

            sbCSV.Append(text);
            if (appendTrailingComma)
                sbCSV.Append(",");
            if (endOfRow)
                sbCSV.AppendLine();
        }
}

If you are looking to export a GridView instead of a DataTable, that explanation is at: http://atakala.com/Browser/Item.aspx?user_id=amos&dict_id=2325 ; much of the code is similar (CSVExportUtility methods)

Amos Zoellner
  • 408
  • 4
  • 10
  • that 1252 charset will fix this too: http://stackoverflow.com/questions/26524301/export-to-excel-names-with-accent-are-not-exported-correctlty? – Luis Valencia Oct 24 '14 at 06:55