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();
Related
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.
I have a web page in my website that allows me to download the chart from that page and add it to an excel sheet. However, a red x button with the words: "this image cannot currently be displayed" is shown in place of the chart. I have tried many solutions online but all of them show the same outcome.
Here are my codes:
protected void ExcelDl_Click(object sender, EventArgs e) {
string tmpChartName = "test2.jpg";
string imgPath = HttpContext.Current.Request.PhysicalApplicationPath + tmpChartName;
Chart1.SaveImage(imgPath);
string imgPath2 = Request.Url.GetLeftPart(UriPartial.Authority) + VirtualPathUtility.ToAbsolute("~/" + tmpChartName);
Response.Clear();
Response.ContentType = "application/vnd.ms-excel";
Response.AddHeader("Content-Disposition", "attachment; filename=test.xls;");
StringWriter sw = new StringWriter();
HtmlTextWriter hw = new HtmlTextWriter(sw);
string headerTable = #"<Table><tr><td><img src='" + imgPath2 + #"' \></td></tr></Table>";
Response.Write(headerTable);
Response.Write(sw.ToString());
Response.End();
}
Any form of help will be greatly appreciated. Also, do note that I have added the required codes in my Web.config.
We have tried your program and here it’s working fine. Excel downloaded along with image. I have installed in iis and tried with many client machine and it was working fine.
Not sure what’s going on your end. The problem might be wrong image path reference will cause this problem. Print image URL and make sure whether it is correct or not.
Alternate method: instead of using html tags inside the excel cell use XML closing method to render the image inside the excel cell.
Here I have added sample code for the Closed XML methods to render the image in excel. to use this code need to refer the following DLLs
1. ClosedXML.dll
2. WindowsCore.dll
3. DocumentFormat.OpenXML.dll
4. PresentationCore.dll
Reference Link for Closed XML methods: https://closedxml.codeplex.com/
using (XLWorkbook wb = new XLWorkbook())
{
IXLWorksheet WorkSheet = new IXLWorksheet();
string LogoPath = Server.MapPath("~/App_Themes/Images/logonew.png");
System.Drawing.Bitmap bitmap = new System.Drawing.Bitmap(LogoPath);
if (bitmap != null)
{
var stream = new System.IO.MemoryStream();
bitmap.Save(stream, System.Drawing.Imaging.ImageFormat.Gif);
if (stream != null)
{
stream.Position = 0;
XLPicture pic = new XLPicture
{
NoChangeAspect = true,
NoMove = true,
NoResize = true,
ImageStream = stream,
Name = "Logo",
EMUOffsetX = 4,
EMUOffsetY = 6
};
XLMarker fMark = new XLMarker
{
ColumnId = 1,
RowId = 1
};
pic.AddMarker(fMark);
WorkSheet.AddPicture(pic);
}
}
Response.Clear();
Response.Buffer = true;
Response.Charset = "";
Response.ContentType = "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet";
Response.AddHeader("content-disposition", "attachment;filename=test.xls");
using (MemoryStream MyMemoryStream = new MemoryStream())
{
wb.SaveAs(MyMemoryStream);
MyMemoryStream.WriteTo(Response.OutputStream);
Response.Flush();
Response.End();
}
}
Please check and let me know your comments.
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();
}
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 ?
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.