Creating an excel file with EPPlus, but it is always read-only - c#

I'm creating/sending a file with EPPlus like this:
using (ExcelPackage package = new ExcelPackage())
{
ExcelWorksheet worksheet = package.Workbook.Worksheets.Add("Sheet");
... //create file here
Response.Clear();
Response.ContentType = "application/xlsx";
Response.AddHeader("content-disposition", "attachment; filename=" + filename + ".xlsx");
Response.BinaryWrite(package.GetAsByteArray());
Response.End();
}
Everything works fine, except the file always comes back as read-only, and I can't figure out why. Within the "package" object, there is a file object with a IsReadOnly field, but the file object is null. I anticipate that I'm not creating the xcel file correctly, but this is the only way I could figure out how to create the file well. Initially I was using a memory stream, but doing that, I ran into issues when the excel file was bigger than 50 rows.
Edit/update: So I initiate the code block by clicking a button "Download as Excel File". The code runs, creating the file, and the user is prompted with a "You have chose to open: thisismyexcelfile.xlsx which is a: XLSX file (size here) from: mywebsite. What should firefox do with this file?" After selecting "Open with OpenOffice Calc" the spreedsheet opens and displays appropriately but is read-only.
Edit/update: I checked the file properties with OpenOffice. Under Properties/Security there is a "Open file Read Only" checkbox, but it is already unchecked and disabled.

I found this example, I see 3 main differences
Response.ContentType is set to application/vnd.openxmlformats
Response.WriteFile is used instead or Response.BinaryWrite
In this example the file is being saved to the server, sent as response and then deleted
void ExportToExcel(Event evt)
{
var fileInfo = new FileInfo(Path.GetTempPath() + "\\" +
DateTime.Now.Ticks + ".xlsx");
using (var xls = new ExcelPackage(fileInfo))
{
var sheet = xls.Workbook.Worksheets.Add(evt.Title);
sheet.Cell(1, 1).Value = "First name";
sheet.Cell(1, 2).Value = "Last name";
sheet.Cell(1, 3).Value = "E-mail";
sheet.Cell(1, 4).Value = "Phone";
sheet.Cell(1, 5).Value = "Registered";
sheet.Cell(1, 6).Value = "Live Meeting";
var i = 1;
foreach(var attendee in evt.Attendees)
{
i++;
var profile = attendee.Profile;
sheet.Cell(i, 1).Value = profile.FirstName;
sheet.Cell(i, 2).Value = profile.LastName;
sheet.Cell(i, 3).Value = profile.Email;
sheet.Cell(i, 4).Value = profile.Phone;
sheet.Cell(i, 5).Value = att.Created.ToString();
sheet.Cell(i, 6).Value = att.LiveMeeting.ToString();
}
xls.Save();
}
Response.Clear();
Response.ContentType = "application/vnd.openxmlformats";
Response.AddHeader("Content-Disposition",
"attachment; filename=" + fileInfo.Name);
Response.WriteFile(fileInfo.FullName);
Response.Flush();
if (fileInfo.Exists)
fileInfo.Delete();
}

From the comments, I was able to verify that saving the file to a location on the disk and opening it directly did not open the file as read-only, implying the problem was not with the code, but the browsers handling of files downloaded from the internet.

Related

Downloading a file with webforms and EPPlus

I am implementing a small export feature for a legacy webforms application.
My export code right now is only headers (just testing the that I can successfully create a file):
public MemoryStream Export()
{
var result = new MemoryStream();
using (var p = new ExcelPackage())
{
var ws = p.Workbook.Worksheets.Add("Contacts");
var col = 1;
ws.Cells[1, col++].Value = "ID";
ws.Cells[1, col++].Value = "First Name";
ws.Cells[1, col++].Value = "Last Name";
ws.Cells[1, col++].Value = "Email";
ws.Cells[1, col++].Value = "Phone";
ws.Cells[1, col++].Value = "Address";
p.SaveAs(result);
}
return result;
}
Here is the button handler:
var ms = Export();
ms.WriteTo(HttpContext.Current.Response.OutputStream);
HttpContext.Current.Response.ContentType = "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet";
HttpContext.Current.Response.AddHeader("Content-Disposition", $"attachment;filename=Contacts_{DateTime.Now:yyyyMMddhhmmss}.xlsx");
HttpContext.Current.Response.StatusCode = 200;
// HttpContext.Current.Response.End();
So one issue is that all the examples I find have the HttpContext.Current.Response.End() call at the end of the method, but if I do this, it throws an exception. Commenting this line out seems to work fine but that leads me to my main problem: when the file is saved and then opened in excel, Excel complains there is a problem with the file. My impression is that EPPlus makes well formed files, so what am I missing?
Update #1
I tried directly saving the EPPlus package to disk. That seems to work without issue. So the problem lies somewhere between writing the package to the memorystream and returning the result.
Here is the code that is working for me
var ms = Export();
Response.Clear();
HttpContext.Current.Response.ContentType = "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet";
HttpContext.Current.Response.AddHeader("Content-Disposition", $"attachment;filename=Contacts_{DateTime.Now:yyyyMMddhhmmss}.xlsx");
Response.AddHeader("Content-Length", ms.Length.ToString());
Response.BinaryWrite(ms.ToArray());
Response.End();

Can't download excel file from C#

I'm working on adding Export functionality to an existing site. I've created an Excel file, and I'm able to output it to my local directory, but when I try pushing the file to the user using Response, nothing happens. I've viewed several differnet articles and Stack questions, and none seem to be different from what I have, or work when I apply them.
Here is the code I currently have:
public void Export () {
//Create instance of the database
ExportContext eDB = new ExportContext();
var query = (from x in eDB.EMPLOYEES
select x);
IEnumerable<EMPLOYEES> employees = query.ToList();
//Set filename to Table + date/time
string fileName = "EMPLOYEES" + DateTime.Now.ToShortTimeString() + ".xlsx";
//Create excel package
ExcelPackage excel = new ExcelPackage();
var worksheet = excel.Workbook.Worksheets.Add("Employees");
worksheet.Cells[1, 1].LoadFromCollection(employees, true);
using (var memoryStream = new MemoryStream()) {
//Output the file to the user via download
Response.Buffer = false;
Response.ContentType = "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet";
Response.AddHeader("content-disposition", "attachment; filename=" + fileName);
excel.SaveAs(memoryStream);
memoryStream.WriteTo(Response.OutputStream);
Response.Flush();
Response.Close();
Response.End();
}
}
Any help will be appreciated. Thanks.

Open ExcelPackage Object with Excel application without saving it on local file path

I have a text file with some information and I convert it to ExcelPackage Object using EPPlus, now I want to know if there is a way to open this object with excel without saving it to a local file? if is not possible can I use a temp directory to save it into a file, and then open it?
If you are talking about a windows app, you could just use something like System.IO.Path.GetTempPath(). You can get more info from here:
How to get temporary folder for current user
So, something like this:
[TestMethod]
public void TempFolderTest()
{
var path = Path.Combine(Path.GetTempPath(), "temp.xlsx");
var tempfile = new FileInfo(path);
if (tempfile.Exists)
tempfile.Delete();
//Save the file
using (var pck = new ExcelPackage(tempfile))
{
var ws = pck.Workbook.Worksheets.Add("Demo");
ws.Cells[1, 2].Value = "Excel Test";
pck.Save();
}
//open the file
Process.Start(tempfile.FullName);
}
if you are talking web you shouldn't need to save it all, just send it via Response:
using (ExcelPackage pck = new ExcelPackage())
{
var ws = pck.Workbook.Worksheets.Add("Demo");
ws.Cells[1, 2].Value = "Excel Test";
var fileBytes = pck.GetAsByteArray();
Response.Clear();
Response.AppendHeader("Content-Length", fileBytes.Length.ToString());
Response.AppendHeader("Content-Disposition",
String.Format("attachment; filename=\"{0}\"; size={1}; creation-date={2}; modification-date={2}; read-date={2}"
, "temp.xlsx"
, fileBytes.Length
, DateTime.Now.ToString("R"))
);
Response.ContentType = "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet";
Response.BinaryWrite(fileBytes);
Response.End();
}

Error while reading and saving the excel file on serverside

I have tried the below coding for generating excel file on serverside.
C# CODING:
public void ReadandOpenExcel(DirectoryInfo outputDir)
{
//FileInfo newFile = new FileInfo(outputDir.FullName + #"\New Microsoft Excel Worksheet.xlsx");
var ExistFile = Server.MapPath("~/excelsample.xlsx");
var File = new FileInfo(ExistFile);
using (ExcelPackage package = new ExcelPackage(File))
{
package.Load(new FileStream(ExistFile, FileMode.Open));
ExcelWorksheet workSheet = package.Workbook.Worksheets["Sheet1"];
workSheet.Cells["A8"].Value = "kevin";
package.Save();
Response.Clear();
Response.ContentType = "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet";
Response.AddHeader("Content-Disposition", "attachment; filename=ProposalRequest.xslx");
**Response.BinaryWrite(package.GetAsByteArray());**
// myMemoryStream.WriteTo(Response.OutputStream); //works too
Response.Flush();
Response.Close();
}
}
While running the above code i got an error as : " Package object was closed and disposed, so cannot carry out operations on this object or any stream opened on a part of this package."
ERROR On This Line:
Response.BinaryWrite(package.GetAsByteArray());
Make some way for this coding to move on.
Thanks in advance.
Does it work if you get the bytes before you do the Save ?
Byte[] bin = package.GetAsByteArray();
package.Save();
And then use that value in the Binarywrite;
Response.BinaryWrite(bin);
Maybe it is getting closed on the .Save() call ?

Export Datatable To Excel Format / Extension Error

I generate Excel document in ASP.Net with below code:
if (dataTable.Rows.Count > 0)
{
var tw = new StringWriter();
var hw = new System.Web.UI.HtmlTextWriter(tw);
var dgGrid = new DataGrid();
dgGrid.DataSource = dataTable;
dgGrid.DataBind();
dgGrid.RenderControl(hw);
attachment = "attachment; filename=" + fileName + ".xls";
Response.Charset = "UTF-8";
Response.ContentType = "application/vnd.ms-excel";
Response.AppendHeader("content-disposition", attachment);
outputResponse = tw.ToString();
}
But when I want to open Excel document it gives error:
Error: excel cannot open the file .xls because the file format or
file extension is not valid
How can I solve it?
Either use a reference to the Excel Application object to create an actual excel file, use one of the many codeplex based projects to create an Excel spreadsheet or most easily create a CSV file from your datagrid and return that, which many users computers will prompt them to open in Excel.
Just tried your code, with exception of the last line, which I've changed:
var tw = new StringWriter();
var hw = new System.Web.UI.HtmlTextWriter(tw);
var dgGrid = new DataGrid();
dgGrid.DataSource = dataTable;
dgGrid.DataBind();
dgGrid.RenderControl(hw);
var attachment = "attachment; filename=" + fileName + ".xls";
Response.Charset = "UTF-8";
Response.ContentType = "application/vnd.ms-excel";
Response.AppendHeader("content-disposition", attachment);
// outputResponse = tw.ToString();
Response.Output.Write(tw.ToString());
Response.Flush();
Response.End();
My datatable is a 2-col table with simple data (letters and numbers)and it is opened as it should.
You will get the message that says:
The file you are trying to open'yourfilename.xls', is in a different
format thahn specified by the file extension. Verify that the file is
not corrupted and is from a trusted source before opening the file. Do
you want to open the file now?
After clicking OK the file opens just fine.

Categories

Resources