Error dialog displayed when opening an excel file generated with EPPlus - c#

I am creating an Excel file using the EPPlus library. When I create file and open up the file, the following pop up message shows:
We found a problem with some content in 'ExcelDemo.xlsx'. Do you want us to try to recover as much as we can? If you trust the source of this workbook, Click Yes
I am using following code
using (ExcelPackage pck = new ExcelPackage())
{
//Create the worksheet
ExcelWorksheet ws = pck.Workbook.Worksheets.Add("Demo");
//Load the datatable into the sheet, starting from cell A1. Print the column names on row 1
ws.Cells[1, 2].Value = "Excel Download";
Response.ContentType = "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet";
Response.AddHeader("content-disposition", "attachment; filename=ExcelDemo.xlsx");
Response.BinaryWrite(pck.GetAsByteArray());
}
Is there problem in my code or is this an Excel issue?

In my case the problem was in calling
package.Save();
and using
Response.BinaryWrite(package.GetAsByteArray());
at the same time.
When you call package.GetAsByteArray() it perfoms following operations internally:
this.Workbook.Save();
this._package.Close();
this._package.Save(this._stream);
So, calling package.Save two times leads to this error when opening in Excel.

At the start, you need to add in a:
Response.Clear();
Then at the end add a
Response.End();

I will share my solution. I am using a template excel file and then create new excel from it.
Receiving the same error. My code was
using (Stream newFileStream = File.Open(this.tempFilePath, FileMode.OpenOrCreate, FileAccess.ReadWrite, FileShare.ReadWrite))
using (Stream originalFile = File.Open(this.initialFilePath, FileMode.Open, FileAccess.Read, FileShare.ReadWrite))
using (ExcelPackage excelPackage = new ExcelPackage(newFile, template))
{
// ... Do work here
}
I had to change code to:
FileInfo intialInfo = new FileInfo(this.initialFilePath);
FileInfo tempFileInfo = new FileInfo(this.tempFilePath);
using (ExcelPackage excelPackage = new ExcelPackage(tempFileInfo, intialInfo))
{
//... Do work here
}
Also I am using ASP MVC and the response is:
byte[] result = exporter.GetBytesFromGeneratedExcel();
return this.File(result, "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet", "Test.xlsx");

In my case, problem was data table name which I did not set earlier.
Try this one,
dt.TableName = "ExcelSheet1";

I was having this problem because I was writing a string larger than 32,767 characters into a single cell. Excel doesn't like this, but EPPlus won't stop you from doing it.

My code was updated... and was getting the same error.... and I finally found my solution
Original Code:
public static void ExportToExcel(HttpContext ctx, DataTable tbl, string fileName)
{
try
{
using (ExcelPackage pck = new ExcelPackage())
{
//Create the worksheet
ExcelWorksheet ws = pck.Workbook.Worksheets.Add(fileName);
//Load the datatable into the sheet, starting from cell A1. Print the column names on row 1
ws.Cells["A1"].LoadFromDataTable(tbl, true);
int rowCount = tbl.Rows.Count;
List<int> dateColumns = new List<int>();
foreach (DataColumn d in tbl.Columns)
{
if (d.DataType == typeof(DateTime))
dateColumns.Add(d.Ordinal + 1);
}
CultureInfo info = new CultureInfo(ctx.Session["Language"].ToString());
foreach (int dc in dateColumns)
ws.Cells[2, dc, rowCount + 1, dc].Style.Numberformat.Format = info.DateTimeFormat.ShortDatePattern;
//Write it back to the client
ctx.Response.Clear();
ctx.Response.AddHeader("content-disposition", "attachment; filename=" + fileName + ".xlsx");
ctx.Response.ContentType = "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet";
ctx.Response.Buffer = false;
ctx.Response.BufferOutput = false;
ctx.Response.BinaryWrite(pck.GetAsByteArray());
ctx.Response.End();
}
}
catch (Exception EX)
{
ctx.Response.Write(EX.ToString());
}
}
Code update:
catch (Exception EX)
{
if (!(EX is System.Threading.ThreadAbortException))
{
ctx.Response.Write(EX.ToString());
}
}
IT WORKED!

A solution I came up with was just returning the file object in the controller. The first argument should be the byte array (file), the second argument is the content type, and the last argument is the filename (in my case "report.xlsx").
return File(file, "application/octet-stream", fileName);
Hope this helped.

Related

Using OpenXML read the existing file and append some rows with data, then return it as bytes so as to download the form

public static byte[] AddDataToPredifinedFormat(string path, string sheetName = "")
{
byte[] fileBytes = null;
var employee = new List<Employee>
{
new Employee{Name = "XYZ", Number = "12345"},
new Employee{Name = "ABC", Number = "12345"}
};
try
{
using (MemoryStream ms = new MemoryStream())
{
using (SpreadsheetDocument document = SpreadsheetDocument.Open(ms, false))
{
WorkbookPart wbPart = document.WorkbookPart;
IEnumerable<Sheet> sheets = wbPart.Workbook.GetFirstChild<Sheets>().Elements<Sheet>();
string sheetId = sheetName != "" ? sheets.Where(q => q.Name == sheetName).First().Id.Value : sheets.First().Id.Value;
WorksheetPart wsPart = (WorksheetPart)wbPart.GetPartById(sheetId);
SheetData sheetData = wsPart.Worksheet.GetFirstChild<SheetData>();
foreach (var x in employee)
{
Row newRow = new Row();
Cell cell = new Cell();
cell.CellValue = new CellValue(x.Name.ToString());
cell.StyleIndex = 0;
newRow.AppendChild(cell);
sheetData.AppendChild(newRow);
}
wbPart.Workbook.Save(ms);
fileBytes = ms.ToArray();
}
}
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
}
return fileBytes;
}
Reading the existing file and appending rows but on downloading the file, Excel app shows it's corrupted.
Using OpenXML read the existing file and append some rows with data, then return it as bytes so as to download the form
I think in order to return the sheet you need to need to refactor code a little. Instead of expecting the memory stream to write directly to array and download file wont help,
What i did is in my code:
Write data to stream and read that back. So you need to return the updated stream
Write the stream data to ExcelPackage
Something like this
using OfficeOpenXml;
Stream stream = new MemoryStream(<process and return your steam>);
using (ExcelPackage package = new ExcelPackage(stream))
{
//write any more extra data to sheet
return package.GetAsByteArray();
}
Important bit to notice is : package.GetAsByteArray();
Can you try moving fileBytes = ms.ToArray(); to outside of the inner using block?
I have very similar code to this for modifying WordprocessingDocuments with OpenXML but I don't use MemoryStream. I File.Copy the original to a temporary file, modify, save and then load the byte[] from the temporary file for streaming.

EPPlus not returning correct file format

Hello I'm using EPPlus to generate Excel file but what I get is bad encoded file as shown in screenshot
Here is my code snippet:
var stream = new MemoryStream();
using (var package = new ExcelPackage(stream))
{
var worksheet = package.Workbook.Worksheets.Add("Title");
worksheet.Cells[1, 1].Value = "Hello";
package.Save();
}
stream.Position = 0;
return File(stream, "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet", "bankroll-transaction.xlsx");
Maybe something like this
return File(stream, System.Net.Mime.MediaTypeNames.Application.Octet, "XXXX.xlsx")

Creating multiple sheets of excel from c# using streamwriter

I'm using the streamwriter to create an excel file. but the problem is that I didn't find a way to create multiple sheets and specify their names from c#. Also I wanted to draw a chart on excel using streamwriter. So does anybody have an idea how to do both things using streamwriter and not excel instance??
My code is like this:
String sPath = Environment.GetEnvironmentVariable("TEMP") + "\\Synthese.xls";
FileStream oFile = new FileStream(sPath, FileMode.Create);
StreamWriter oWriter = new StreamWriter(oFile, System.Text.Encoding.UTF8);
oWriter.WriteLine("<table border='1' border-color='#ffffff' style=font-weight:bold;><tr>");
...
oWriter.Close();
oFile.Close();
FileInfo myFile = new FileInfo(sPath);
Response.Clear();
Response.AddHeader("Content-Disposition", "attachment; filename=" + myFile.Name);
Response.AddHeader("Content-Length", myFile.Length.ToString());
Response.ContentType = "application/octet-stream";
Response.WriteFile(myFile.FullName);
Response.Flush();
Response.End();
Any help is highly appreciated.
It looks like you're trying to write pseudo-HTML to a xls file and hope it works... I'd be surprised if Excel even opens it.
You are better off using a proper tool for the job.
I suggest looking at EPPlus which allows you to create excel documents in C# with all the features you are describing.
Example lifted from the codeplex site:
FileInfo newFile = new FileInfo(outputDir.FullName + #"\sample6.xlsx");
ExcelPackage pck = new ExcelPackage(newFile);
//Add the Content sheet
var ws = pck.Workbook.Worksheets.Add("Content");
ws.View.ShowGridLines = false;
//Headers
ws.Cells["B1"].Value = "Name";
ws.Cells["C1"].Value = "Size";
ws.Cells["D1"].Value = "Created";
ws.Cells["E1"].Value = "Last modified";
ws.Cells["B1:E1"].Style.Font.Bold = true;
Additionally it is advisable to use using statements when using IDisposable classes such as FileStream:
using (var stream = new FileStream(path, FileMode.Create))
{
// ... stuff using stream in here
}

How to write data to excel file and download it in asp.net

i have develop an application for online store in which different store keep there catalog online. but i have to develop an functionality for download there catalog in xls file for that i have my data in datatable which i have to write in dynamically generated xls file and download it.
for that i have try fallowing :
DataTable ProductDetails = sql.ExecuteSelectCommand("SELECT * FROM Products_Details_View WHERE Supp_Id = " + Session["SuppID"].ToString() + " and Is_Available = 1");
Response.ClearContent();
Response.AddHeader("content-disposition", "attachment;filename=Catalog.xls");
Response.ContentType = "application/excel";
Response.Write(ProductDetails);
Response.End();
i refer it here
but am not getting any thing
please help to get out of it.
I use the EPPlus package, which you can install via Nuget. It allows you to load data onto an Excel worksheet directly from your datatable, and it includes support for things like formatting on the worksheet (fonts, column widths etc). See their
documentation page here on using it inside a web application.
For your case, I would suggest something like:
DataTable ProductDetails = sql.ExecuteSelectCommand("SELECT * FROM Products_Details_View WHERE Supp_Id = " + Session["SuppID"].ToString() + " and Is_Available = 1");
using (ExcelPackage pck = new ExcelPackage())
{
//Create the worksheet
ExcelWorksheet ws = pck.Workbook.Worksheets.Add("Demo");
//Load the datatable into the sheet, starting from cell A1.
//Print the column names on row 1
ws.Cells["A1"].LoadFromDataTable(ProductDetails, true);
//Write it back to the client
Response.ContentType = "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet";
Response.AddHeader("content-disposition", "attachment; filename=ProductDetails.xlsx");
Response.BinaryWrite(pck.GetAsByteArray());
}
Try this
string attachment = "attachment; filename=xxxx" + DateTime.Now + ".xls";
Response.ClearContent();
Response.AddHeader("content-disposition", attachment);
Response.ContentType = "application/ms-excel";
StringWriter stw = new StringWriter();
HtmlTextWriter htextw = new HtmlTextWriter(stw);
ProductDetails.RenderControl(htextw);
GridView dg = new GridView(); //Create an empty Gridview to bind to datatable.
dg.AutoGenerateColumns = true;
dg.DataSource = ProductDetails;
dg.DataBind();
dg.RenderControl(htw);
Response.Write(stw.ToString());
stw.Close();
Response.End();

Download EXCEL file from ASP.NET page without Generating physical file on server (On The Fly)

I am trying to export C# DataTable to EXCEL file on the fly (without creating physical file) using Microsoft Office EXCEL INTEROP and download it through asp.net webpage through Response object. I am able to generate memorystream using the library But somehow the file is not getting saved through the memory stream. Reference code is given below. You will be required to take reference for DocumentFormat.OpenXml.dll & WindowsBase.DLL (that you can download from microsoft site).
Any Idea how to resolve the problem ? ? ?
Private void DownloadFile()
{
DataSet objTable = ReadTableFromViewstate();
if (objTable != null && objTable.Rows.Count > 0)
{
string strDownloadableFilename = "TestExcelFileName.xls";
MemoryStream fs1 = new MemoryStream();
if (CreateExcelFile.CreateExcelDocument(objTable, fs1))
{
Response.Clear();
byte[] data1 = new byte[fs1.Length];
fs1.Read(data1, 0, data1.Length);
fs1.Close();
Response.ContentType = "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet";
Response.AddHeader("Content-Disposition", string.Format("attachment; filename={0}", strDownloadableFilename));
Response.BinaryWrite(data1); ;
Response.End();
}
else
{
LblErrorMessage.Text = "Error Exporting File.";
}
}
}
..
public static bool CreateExcelDocument(DataSet ds, System.IO.Stream excelFileStream)
{
try
{
using (SpreadsheetDocument document = SpreadsheetDocument.Create(excelFileStream, SpreadsheetDocumentType.Workbook))
{
CreateParts(ds, document);
}
Trace.WriteLine("Successfully created: " + excelFileStream);
return true;
}
catch (Exception ex)
{
Trace.WriteLine("Failed, exception thrown: " + ex.Message);
return false;
}
}
..
private static void CreateParts(DataSet ds, SpreadsheetDocument document)
{
WorkbookPart workbookPart = document.AddWorkbookPart();
Workbook workbook = new Workbook();
workbookPart.Workbook = workbook;
// If we don't add a "WorkbookStylesPart", OLEDB will refuse to connect to this .xlsx file !
WorkbookStylesPart workbookStylesPart = workbookPart.AddNewPart<WorkbookStylesPart>("rIdStyles");
Stylesheet stylesheet = new Stylesheet();
workbookStylesPart.Stylesheet = stylesheet;
Sheets sheets = new Sheets();
// Loop through each of the DataTables in our DataSet, and create a new Excel Worksheet for each.
uint worksheetNumber = 1;
foreach (DataTable dt in ds.Tables)
{
// For each worksheet you want to create
string workSheetID = "rId" + worksheetNumber.ToString();
string worksheetName = dt.TableName;
WorksheetPart worksheetPart = workbookPart.AddNewPart<WorksheetPart>(workSheetID);
WriteDataTableToExcelWorksheet(dt, worksheetPart);
Sheet sheet = new Sheet() { Name = worksheetName, SheetId = (UInt32Value)worksheetNumber, Id = workSheetID };
sheets.Append(sheet);
worksheetNumber++;
}
workbook.Append(sheets);
}
Thanks to All, Finally I Got solution of my problem. I just replaced following line of code:
byte[] data1 = new byte[fs1.Length];
fs1.Read(data1, 0, data1.Length);
fs1.Close();
with this line
byte[] data1 = fs1.ToArray();
and my problem got resolved.
After finishing writing to the memory stream, you need to set back the pointer to its origin before reading it.
fs1.Seek(0, SeekOrigin.Begin);

Categories