How to remove export to excel warning when exporting datatable - c#

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:

There are two sure ways to remove the warning.
Build a valid .xlsx file using the OpenXML API or EPPlus API (EPPlus is easier and actually supports OleDB imports)
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)

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:
How to Suppress Extension Warning in Excel
How do you generate an Excel 2007 file in ASP.NET without getting a warning message?
How to avoid warning on opening a programmatically generated Excel file

Related

Export Grid Data in a user control to excel on button click

I have a user control with a Grid. Now I have added an export to excel button on the Same user grid just above the grid to enable user to export the corresponding Grid's data to Excel. I wrote the following function on button click even t in User control.
protected void Home_ExportExcel_Click(object sender, EventArgs args)
{
DataTable resultTbl = new DataTable();
if (this.HomeGridDataSource != null)
resultTbl = this.HomeGridDataSource as DataTable;
Download(resultTbl, this.MasterPage.CurrentLibrary);
}
the Download Function is
private void Download(DataTable tb)
{
string attachment = "attachment; filename=HomeGridData" + DateTime.Now.ToString() + ".xls";
Response.ClearContent();
Response.AddHeader("content-disposition", attachment);
Response.ContentType = "application/vnd.ms-excel";
string tab = "";
foreach (DataColumn dc in tb.Columns)
{
Response.Write(tab + dc.ColumnName);
tab = "\t";
}
Response.Write("\n");
int i;
foreach (DataRow dr in tb.Rows)
{
tab = "";
for (i = 0; i < tb.Columns.Count; i++)
{
Response.Write(tab + dr[i].ToString());
tab = "\t";
}
Response.Write("\n");
}
Response.End();
}
Now I get the response for the request as a text format but I need this to be downloaded to the user machine with the Grid data.
I also tried generating .xml file with the Excel styles etc.. but I get the Same result as a text format in response object but I am expecting it to be downloaded.
What am I missing here?
Setting up content type as Excel file is not enough for client to consider response as a Excel file. Your server responds by textual information that is treated by client as a common response. Even though user saves your response to Excel file, the file will not be compliant with the format because it is text.
The better way to work this out is to generate an Excel file using some library. For example., EPPlus.
Using that library you can generate an Excel file in memory (without creating a physical file on disk) and then return it as a stream using Response.OutputStream.Write. A good example of how to respond by stream\file is in the following topic.

C# Export to Excel xls

I have a method that currently exports the results of a stored procedure to a CSV file. I've been tasked with altering it to export to XLS but I'm having some trouble.
The code:
protected void ExportFundingSummaryToExcelSA(Object sender, EventArgs e)
{
const string fileName = "METT Dashboard - Funding Summary";
const string rowFormat = "{0},{1},{2},{3},{4},{5}\n";
Response.Clear();
Response.Buffer = true;
Response.AddHeader("content-disposition", "attachment;filename=" + fileName + ".csv");
Response.Charset = "";
Response.ContentType = "text/csv";
GetCompanyGroupCode();
var sb = new StringBuilder();
sb.AppendFormat(rowFormat, "Sector", "Product Line", "Program Number", "Program Description","Participating Companies", "Gross");
var customerId = CurrentUser.Company.Id;
var year = 2015;
// Set Title Row
Response.Write(year + " Products Lines for: " + CurrentUser.Company.Name + " (" + customerId + ")\n");
// Set Generated Date (Report Created on: 9/29/2004 3:33:32 PM)
Response.Write("Report Created on: " + System.DateTime.Now.ToString() + "\n\n\n");
var fundingData = GetFundingData();
if (fundingData != null)
{
if (fundingData.Summary != null && fundingData.Summary.Count > 0)
{
var summaries = MoveSetAsidesDown(fundingData.Summary);
for (var i = 0; i < summaries.Count; i++)
{
if (fundingData.Programs != null && fundingData.Programs.Count > 0)
{
foreach (var program in fundingData.Programs)
{
if (program.PlId == summaries[i].PlId)
{
sb.AppendFormat(rowFormat,
SharePointUtil.ToCsvFriendly(summaries[i].SectorName),
SharePointUtil.ToCsvFriendly(summaries[i].PlName),
SharePointUtil.ToCsvFriendly(program.TargetId.ToString()),
SharePointUtil.ToCsvFriendly(program.TargetName),
SharePointUtil.ToCsvFriendly(program.ParticipantsCount.ToString()),
SharePointUtil.ToCsvFriendly(program.AmountAllocated.ToString("$###,###,###,##0")));
}
}
}
}
}
}
Response.Write(sb.ToString());
Response.Flush();
Response.End();
}
The big catch is the data manipulation once the data comes back from GetFundingData, I have to do it like that because our DBA is out and I need to knock this out. I thought I'd be able to just change the content type but that blows it up. Any help would be appreciated.
I think the problem is your trying to use CSV formatting to create a XLS file. CSV uses a text based formatting with commas separating the data. XLS uses a binary style of formatting. Because XLS is a Microsoft file format, you will need to use Excel's Object Library to create the files. I do not know if you have the option, but if you can include EPPlus in your application, EPPlus can create, open, and edit XLSX files. XLSX is not XLS, but any version of Excel after the 2007 version can read both types.
[Edit]
Thank you Scott Chamberlain for pointing out that TrevorGoodchild is using a Sharepoint web service. As Scott Chamberlain has pointed out in his comment above, Open XML SDK is an option when using an IIS web service. In addition, because EPPlus does not use COM Interop it may also be usable in your application.

How to export GridView to excel using OpenXML in c#? [closed]

Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 6 years ago.
Improve this question
I know people asked similar questions already. But the solutions are not what I am looking for. For my case, our GridView holds at least a million of records. In addition, our customer doesn't like the warning message from excel 2007. Because of the warning message, we cannot use the most common way that uses GridView.RenderControl(). So we decided to try OpenXML. But from all the sample codes I have found, to create an excel file using OpenXML, it seems that you have to loop each row&column of the GridView and write to each cell of an excel file. It will take a good amount of time. Does any one know if there is better/faster solution? Also, we cannot use third party DLLs because of security reason. Thanks.
here is a method that I use to Export DataTable to Excel I created a class public static class Extensions to house these methods
internal static void ExportToXcel_MyDataTable(DataTable dt, string fileName, Page page)
{
var recCount = dt.Rows.Count;
RemoveHtmlSpecialChars(dt);
fileName = string.Format(fileName, DateTime.Now.ToString("MMddyyyy_hhmmss"));
var xlsx = new XLWorkbook();
var ws = xlsx.Worksheets.Add("Some Report Name");
ws.Style.Font.Bold = true;
ws.Cell("C5").Value = "MY TEST EXCEL REPORT";
ws.Cell("C5").Style.Font.FontColor = XLColor.Black;
ws.Cell("C5").Style.Font.SetFontSize(16.0);
ws.Cell("E5").Value = DateTime.Now.ToString("MM/dd/yyyy HH:mm");
ws.Range("C5:E5").Style.Font.SetFontSize(16.0);
ws.Cell("A7").Value = string.Format("{0} Records", recCount);
ws.Style.Font.Bold = false;
ws.Cell(9, 1).InsertTable(dt.AsEnumerable());
ws.Row(9).InsertRowsBelow(1);
// ws.Style.Font.FontColor = XLColor.Gray;
ws.Columns("1-8").AdjustToContents();
ws.Tables.Table(0).ShowAutoFilter = true;
ws.Style.Alignment.Horizontal = XLAlignmentHorizontalValues.Center;
DynaGenExcelFile(fileName, page, xlsx);
}
private static void DynaGenExcelFile(string fileName, Page page, XLWorkbook xlsx)
{
page.Response.ClearContent();
page.Response.ClearHeaders();
page.Response.ContentType = "application/vnd.ms-excel";
page.Response.AppendHeader("Content-Disposition", string.Format("attachment;filename={0}.xlsx", fileName));
using (MemoryStream memoryStream = new MemoryStream())
{
xlsx.SaveAs(memoryStream);
memoryStream.WriteTo(page.Response.OutputStream);
}
page.Response.Flush();
page.Response.End();
}
If you have Html / special characters in the DataTable this method will remove them replacing the row data with string.Empty
/// <summary>
/// Remove all HTML special characters from datatable field if they are present
/// </summary>
/// <param name="dt"></param>
private static void RemoveHtmlSpecialChars(DataTable dt)
{
for (int rows = 0; rows < dt.Rows.Count; rows++)
{
for (int column = 0; column < dt.Columns.Count; column++)
{
dt.Rows[rows][column] = dt.Rows[rows][column].ToString().Replace(" ", string.Empty);
}
}
}

How to export all the source code from Visual Studio into a text file?

I have a relatively large Visual Studio solution.
I need to export all the source code into a text file. I would also want to include a file name somewhere. How can I do so?
For example if I have a type
namespace MyProject.Core
{
/// <summary>
/// Enumerates possible record status
/// </summary>
public enum RecordType
{
NonWearTime = 0,
WearTime = 1,
NotClassified = 2
}
}
I want this to go to the output.txt file (or any other text format) and appear like so
//***********************************
//Filename: RecordType.cs
//***********************************
namespace MyProject.Core
{
/// <summary>
/// Enumerates possible record status
/// </summary>
public enum RecordType
{
NonWearTime = 0,
WearTime = 1,
NotClassified = 2
}
}
All the other types shall just be appended to the end of the file. I tried Resharper, but its header file options can only contain static text (I tried Filename: $FILENAME$) and the template option only applies to the newly created classes.
Folks, this is a study project, where I have to provide the source code along with a thesis.
This should do the trick
string rootPath = #"path you your root folder";
var header = "***********************************" + Environment.NewLine;
var files = Directory.GetFiles(rootPath, "*.cs", SearchOption.AllDirectories);
var result = files.Select(path => new { Name = Path.GetFileName(path), Contents = File.ReadAllText(path)})
.Select(info =>
header
+ "Filename: " + info.Name + Environment.NewLine
+ header
+ info.Contents);
var singleStr = string.Join(Environment.NewLine, result);
Console.WriteLine ( singleStr );
File.WriteAllText(#"C:\output.txt", singleStr, Encoding.UTF8);
Remarks: if you experience performance or memory inefficiencies, try to use StringBuilder instead and set it's Capacity at the start to the sum of all files contents. This will eliminate lots of redundant strings, created in last Select method.
I would go for a homemade solution.
This helps you get into a String the content of each file.
using System.IO;
...
foreach (string file in Directory.EnumerateFiles(folderPath, "*.cs"))
{
string contents = File.ReadAllText(file);
}
You have the filename, so you can append it at the beginning.
All you still need to do is to parse through all directories.
public void DirSearch(string root)
{
foreach (string file in Directory.EnumerateFiles(root, "*.cs"))
{
string contents = File.ReadAllText(file);
// Write to your outputfile once you've happened what you want in your header.
}
foreach (string d in Directory.GetDirectories(root))
{
DirSearch(d);
}
}
As a none code soloution how about trying a windows command line to merge all files into one.
e.g. copy /b *.cs newfile.txt
https://superuser.com/questions/111825/any-command-line-or-batch-cmd-to-concatenate-multiple-files
Admittedly its quick and dirty, but it might produce what you require with some tailoring
I would write a simple console app to do that. It would search for all files with a *.cs extension, make the necessary modification and then save the file to the desired location. You can loop through directories iteratively using Directory.EnumerateDirectories().

Create a .csv file in C#

Alright I want to create a .csv file in C#. I have been looking around and noticed a lot of people are using the system.IO.memorystream and system.io.streamwriter.
The problem is this: I have a web application. I want to give the user the ability to export to excel. Problem is, Excel cannot be installed on the server (don't ask). I want to be able to write an .csv sheet export for a report. Now, the reports headers and data will be different for all of the reports (looping through will solve this). Anybody have an example or better resources for me to go through?
This the approach i normally take. Probably not the most efficient though.
/// <summary>
/// Generates the contents of the log file.
/// </summary>
/// <returns>The contents of the log file.</returns>
internal string GenerateLogFile()
{
StringBuilder csvExport = new StringBuilder();
csvExport.AppendLine(Resources.CSVHeader);
foreach (DataRow row in this.logEntries.Rows)
{
csvExport.AppendLine(
string.Format(
"\"{0}\",\"{1}\",\"{2}\",\"{3}\",\"{4}\",\"{5}\",\"{6}\",\"{7}\",\"{8}\", \"{9}\"",
row[ColumnNames.LogTime], row[ColumnNames.Field1], row[ColumnNames.Field2], row[ColumnNames.Field3], row[ColumnNames.Field4], row[ColumnNames.Field5], row[ColumnNames.Field6], row[ColumnNames.Field7], row[ColumnNames.Field8], row[ColumnNames.Field9]));
}
return csvExport.ToString();
}
/// <summary>
/// Adds the CSV file to the response.
/// </summary>
/// <param name="csvExportContents">The contents of the CSV file.</param>
internal void DisplayLogFile(string csvExportContents)
{
byte[] data = new ASCIIEncoding().GetBytes(csvExportContents);
HttpContext.Current.Response.Clear();
HttpContext.Current.Response.ContentType = "APPLICATION/OCTET-STREAM";
HttpContext.Current.Response.AppendHeader("Content-Disposition", "attachment; filename=Export.csv");
HttpContext.Current.Response.OutputStream.Write(data, 0, data.Length);
HttpContext.Current.Response.End();
}
private void WriteItem<T>(StreamWriter sr, T item)
{
string itemString = item.ToString();
if(itemString.IndexOfAny(new char[] { '"', ',', '\n', '\r' }) != -1)//skip test and always escape for different speed/filesize optimisation
{
sr.Write('"');
sr.Write(itemString.Replace("\"", "\"\""));
sr.Write('"');
}
else
sr.Write(itemString);
}
private void WriteLine<T>(StreamWriter sr, IEnumerable<T> line)
{
bool first = true;
foreach(T item in line)
{
if(!first)
sr.Write(',');
first = false;
WriteItem(sr, item);
}
}
private void WriteCSV<T>(StreamWriter sr, IEnumerable<IEnumerable<T>> allLines)
{
bool first = true;
foreach(IEnumerable<T> line in allLines)
{
if(!first)
sr.Write('\n');
first = false;
WriteLine(sr, line);
}
}
private void WriteCSV<T>(HttpResponse response, IEnumerable<IEnumerable<T>> allLines)
{
response.ContentType = "text/csv";
WriteCSV(response.Output, allLines);
}
It can be worth also sending a content-disposition header with a recommended filename.
Edit: Of late, with cases where one needs to interspace an action between items in an enumeration (like the comma and newline above), I've preferred that rather keeping a boolean that keeps being checked, I handle the enumerator directly, and then handle the first element separate from the rest. I started doing this as a micro-opt in a efficiency-push but have grown to just find it a better expression of a code-path that differs for the first item. As such, I'd now write the above as:
private void WriteLine<T>(StreamWriter sr, IEnumerable<T> line)
{
using(var en = line.GetEnumerator())
if(en.MoveNext())
{
WriteItem(sr, en.Current);
while(en.MoveNext())
{
sr.Write(',');
WriteItem(sr, en.Current);
}
}
private void WriteCSV<T>(StreamWriter sr, IEnumerable<IEnumerable<T>> allLines)
{
using(var en = allLines.GetEnumerator())
if(en.MoveNext())
{
WriteLine(sr, en.Current);
while(en.MoveNext())
{
sr.Write('\n');
WriteLine(sr, en.Current);
}
}
}
You should be able to use the examples using System.IO.MemoryStream and System.IO.StreamWriter just fine.
Instead of writing the MemoryStream out to a file, you would return it as the ResponseStream in ASP.NET (making sure that you set the appropriate header values so the browser knows that it's downloading a file).
Excel is only required if you are using Office Interop. Using StringWriter, you are simply going to create a file and add some response information. Excel is only required when opening the file.
There is really no magic in creating a CSV file. The only problem with CSV files is that there is not really a standard, and most importers will just implement one particular behavior for the import process. If you are lucky, you will get something that can guess relatively well.
Generating the CSV file is just a matter of printing the lines. As for the actual details, familiarize yourself with:
http://en.wikipedia.org/wiki/Comma-separated_values
That being said, if what you want is to export to Excel, you could use Microsoft's OOXML SDK:
http://msdn.microsoft.com/en-us/library/bb448854.aspx
The OOXML SDK is a C# library that you can use to generate Excel files on the server. The Brian Jones blog is a great resource on how to use this library:
http://blogs.msdn.com/b/brian_jones/
If you don't mind using a 3rd party library and the LGPL license is okay in your project, then FileHelpers is a great tool for this.
This is the function used to create csv file:
private async Task<string> WriteCSV<ViewModel>(IEnumerable<ViewModel> viewModels, string path)
{
Type itemType = typeof(ViewModel);
var props = itemType.GetProperties(BindingFlags.Public | BindingFlags.Instance)
.OrderBy(p => p.Name);
var blobName = string.Empty;
using (var ms = new MemoryStream())
{
using (var writer = new System.IO.StreamWriter(ms))
{
writer.WriteLine(string.Join(", ", props.Select(p => p.Name)));
foreach (var item in viewModels)
{
writer.WriteLine(string.Join(", ", props.Select(p => p.GetValue(item, null))));
}
}
}
}
Otherwise you can refer below link:
https://travelcodingnlotsmore.wordpress.com/2013/06/06/creating-csv-file-from-data-in-list-object-in-c/

Categories

Resources