C# HttpGet response gives me an empty Excel file with EPPlus - c#

I've created an endpoint that generates an Excel file. It's supposed to function as a GET in case I want some other code to POST it to a different endpoint for emailing, or in case I want to just download the Excel file by hitting the endpoint manually in a browser. It's downloading the Excel file, but when I try to open it I see the message "Excel cannot open the file 'blahblah' because the file format or file extension is not valid. Verify that the file has not been corrupted and that the file extension matches the format of the file."
After getting that error, I've tried changing the MIME type in my response content field and/or file extension, and the error goes away and the file opens with the following warning: "The file format and extension of "blah blah" don't match. The file could be corrupted or unsafe. Unless you trust its source, don't open it. Do you want to open it anyway?" If I open it anyway, the file is still empty.
Here is the code where I take the ExcelPackage I created and add it to the response.
var response = HttpContext.Current.Response;
response.ContentType = "application/vnd.openxmlformats- officedocument.spreadsheetml.sheet";
var fileName = string.Format("blahblah-{0}.xls", InstantPattern.CreateWithInvariantCulture("yyyy-dd-M-HH-mm-ss").Format(_clock.Now));
response.AddHeader("content-disposition", string.Format("attachment; filename={0}", fileName));
response.BinaryWrite(excelPackage.GetAsByteArray());
I've tried adding in a different mime type like application/excel. I've tried using the .xlsx file extension instead of xls. Nothing has really worked. I know that the ExcelPackage workbook's worksheets actually have the data I want, though, because when I debug and hover over the objects I see the cell values that I'm expecting to make it into the file. So what am I doing wrong?
I've tried generating the excelPackage in two ways, both while inside a using block. Like this:
using (var excelPackage = new ExcelPackage())
{
// generate and download excel file
}
And also like this:
using (var excelPackage = new ExcelPackage(new FileInfo(fileName)))
{
// generate and download excel file
}

I use this to send the Excel file to the browser.
HttpResponse Response = HttpContext.Current.Response;
//first convert to byte array
byte[] bin = excelPackage.GetAsByteArray();
//clear the buffer stream
Response.ClearHeaders();
Response.Clear();
Response.Buffer = true;
//add the content type
Response.ContentType = "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet";
//set the content length, without it, length is set to -1 and could give errors
Response.AddHeader("content-length", bin.Length.ToString());
//add a filename
Response.AddHeader("content-disposition", "attachment; filename=\"" + fileName + ".xlsx\"");
//send the file to the browser
Response.OutputStream.Write(bin, 0, bin.Length);
//cleanup
Response.Flush();
HttpContext.Current.ApplicationInstance.CompleteRequest();

Related

Why doesn't Response.TransmitFile return my file in my WCF service?

If you could explain me why TransmitFile ain't working, code is simple, I create excel file (.xlsx), save it on server and return file path (via CreateProjectsReport), and then I just want to take file and transmit it to user ....
string filePath = CreateProjectsReport(ProjectIds, items);
System.IO.FileInfo file = new System.IO.FileInfo(filePath);
if (file.Exists)
{
HttpContext context = HttpContext.Current;
try
{
context.Response.Clear();
context.Response.ClearHeaders();
context.Response.ClearContent();
context.Response.AddHeader("Content-Disposition",
"attachment; filename=" + file.Name);
context.Response.AddHeader("Content-Length", file.Length.ToString());
// context.Response.ContentType = "application
// vnd.openxmlformats-officedocument.spreadsheetml.sheet";
context.Response.ContentType = "application/vnd.ms-excel";
context.Response.TransmitFile(file.FullName);
context.Response.Flush();
// context.Response.WriteFile(file.FullName, false);
}
catch (Exception ex)
{
LogException(ex);
}
finally
{
System.IO.File.Delete(filePath);
context.Response.End();
}
}
Result of this code is that file get saved on my server in expected folder (full report is there, I verified excel file that is being generated by method) and on response.Flush() I see file being transmitted on browsers with content length of 30kb as the file length is on server, but once i click save and file gets saved in my download folder it's length is 10kb, opening it with excel I get error: Excel foudn unreadable content in 'filename.xlsx'. Do you want to recover .....
Checking IIS MIME Types, it's set (I tried using both for content type, get same error):
.xls - application/vnd.ms-excel
.xlsx - application/vnd.openxmlformats-officedocument.spreadsheetml.sheet
Does context.Response.TransmitFile suppress my file and doesn't send full content of it? Why does this happen?
EDIT
Through browsers console I can see that in Response.Header property content-length is exact length of file, but once i click Save file, that file size goes from 1kb to 15kb tops, instead of 30kb which is on server (it's like TransmitFile(file.FullName) doesn't Transmit whole file

How to download an Excel file

I want to download an Excel sheet to my specific location not to Download folder.
I tried below code. Then the file is download to the "Download" folder. I need to download this file to a given file path.
string filepath = "D:\";
string strDownloadableFilename = "Test.xlsx"
Using (MemoryStream stream = ExportExcel()){
Response.Clear();
Response.ContentType = "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet";
Response.AddHeader("Content-Disposition", string.Format("attachment; filename={0}", strDownloadableFilename));
stream.WriteTo(Response.OutPutStream); ;
Response.End();
}
The file is download to "Download" folder.
Well there are two things
first of all what you want to achieve can't be done by downoad option it means we can read file and write in system memory as per our desired location but in that case No download popup will see so you have to decide if you need download popup and no desired location or vice versa.

Exporting file gives me an error: Filename is in a different format than specified by the file extension

Here's the export piece of my code:
private void ExportGridView()
{
// Exports the data in the GridView to Excel
// First, fill the datagrid with the results of the session variable
DataTable gridDataSource = (DataTable)Session["SSRegisterSplit"];
DataGrid dgGrid = new DataGrid();
dgGrid.DataSource = gridDataSource;
dgGrid.DataBind();
// Exports the data in the GridView to Excel
string attachment = "attachment; filename=Claim_Details_" + LPI_ID + ".xls";
Response.ClearContent();
Response.AddHeader("content-disposition", attachment);
Response.ContentType = "application/ms-excel";
StringWriter sw = new StringWriter();
HtmlTextWriter htw = new HtmlTextWriter(sw);
dgGrid.RenderControl(htw);
Response.Write(sw.ToString());
Response.End();
}
When it exports, it shows up in my footer automatically with an option to Open or Save.
If I choose "Open", Excel launches and then I get an error box:
The file you are trying to open, 'Claim_Details_1586.xls' is in a
different format than 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?
If I choose 'Yes', it opens the file but not all the records are in it.
Any ideas on what's happening/how to fix it?
EDIT:
Putting a break point in the function, I noticed that when it gets to Response.End(); it throws the error:
Thread Was being Aborted.
I think this is what you want:
Is Response.End() considered harmful?
Don't use Response.End()
Consider using:
Response.Flush()
Response.SuppressContent = True
HttpContext.Current.ApplicationInstance.CompleteRequest()
—————————————————————————————
However. I'm pretty sure that the ”save an html file with .XLS extension” will always result in Excel showing an error.
The alternative is to pick something from http://nugetmusthaves.com/Tag/Excel to create a proper xls file. I've used EPPlus before but this page suggests that ClosedXML will do it for you in 5 lines.
If you aren't familiar with installing NuGet packages, then start here: https://learn.microsoft.com/en-gb/nuget/tools/package-manager-ui

ZIP download contains html content

When I use the following code to download a ZIP file it appears to work. However, when I attempt to open the downloaded ZIP, I get an 'invalid compressed folder' message. When I open the ZIP in notepad I see it is filled with HTML.
string fp = Server.MapPath("directory\\file.zip");
FileInfo file = new FileInfo(fp);
if (file.Exists)
{
Response.ClearContent();
Response.AddHeader("content-disposition","attachment; filename=" + file.Name);
Response.AddHeader("content-length", file.Length.ToString());
Response.ContentType = "application/zip";
Response.TransmitFile(file.FullName);
Response.End();
}
An issue I can't seem to fix that is probably related is when I try to manually type in the address of the file (http://website.com/downloads/file.zip), I get a redirect (http://website.com/login.aspx) even when logged in as the admin. Any pointers in where to look would be greatly appreciated.
Instead of just using Response.ClearContent() also use Response.ClearHeaders() to remove all the current headers as well as the body of the response.
From MSDN, HttpResponse.ClearContent Method:
The ClearContent method does not clear header information.

iTextSharp generated PDF: How to send the pdf to the client and add a prompt?

I have generated a pdf using iTextSharp, when its created it saves automatically in the location provided in my code on the server not on the client side and of course without telling anything to the user.
I need to send it to the client and I need to prompt a dialogue box to ask the user where he wants to save his pdf..
how can i do this please?
this is my pdf code:
using (MemoryStream myMemoryStream = new MemoryStream())
{
Document document = new Document();
PdfWriter PDFWriter = PdfWriter.GetInstance(document, myMemoryStream);
document.AddHeader("header1", "HEADER1");
document.Open();
//..........
document.Close();
byte[] content = myMemoryStream.ToArray();
// Write out PDF from memory stream.
using (FileStream fs = File.Create(HttpContext.Current.Server.MapPath("~\\report.pdf")))
{
fs.Write(content, 0, (int)content.Length);
}
EDIT
this is an example of the result i want
http://examples.extjs.eu/?ex=download
thanks to your replies ,I modified my code to this:
HttpContext.Current.Response.ContentType = "application/pdf";
HttpContext.Current.Response.AppendHeader( "Content-Disposition", "attachment; filename=test.pdf");
using (MemoryStream myMemoryStream = new MemoryStream())
{
Document document = new Document();
PdfWriter PDFWriter = PdfWriter.GetInstance(document, myMemoryStream);
document.AddHeader("Content-Disposition", "attachment; filename=wissalReport.pdf");
document.Open();
//..........
document.Close();
byte[] content = myMemoryStream.ToArray();
HttpContext.Current.Response.Buffer = false;
HttpContext.Current.Response.Clear();
HttpContext.Current.Response.ClearContent();
HttpContext.Current.Response.ClearHeaders();
HttpContext.Current.Response.AppendHeader("content-disposition","attachment;filename=" + "my_report.pdf");
HttpContext.Current.Response.ContentType = "Application/pdf";
//Write the file content directly to the HTTP content output stream.
HttpContext.Current.Response.BinaryWrite(content);
HttpContext.Current.Response.Flush();
HttpContext.Current.Response.End();
but i get this error:
Uncaught Ext.Error: You're trying to decode an invalid JSON String:
%PDF-1.4 %���� 3 0 obj <</Type/XObject/Subtype/Image/Width 994/Height 185/Length 13339/ColorSpace/DeviceGray/BitsPerComponent 8/Filter/FlateDecode>>stream x���|E�
...........
im absolutely sure my itextsharp to create pdf is correct because i can save it on the server, but thats not what i need to do ,when i try to send it to the client i got the error above
thanks in advance
In case of a web application you probably want to stream the pdf as binary to user, that would either open the pdf or prompt user to save the file.
Remember pdf generation is happening at server, even if user provides the path it won't be of any use on server. See following links -
How To Write Binary Files to the Browser Using ASP.NET and Visual C# .NET
In your case you are generating the file and hence will already be having a binary stream instead of file, hence you can directly use Response.BinaryWrite instead of Response.WriteFile.
Modified sample:
Response.Buffer = false;
Response.Clear();
Response.ClearContent();
Response.ClearHeaders();
//Set the appropriate ContentType.
Response.ContentType = "Application/pdf";
//Write the file content directly to the HTTP content output stream.
Response.BinaryWrite(content);
Response.Flush();
Response.End();
You need to send a content disposition header to the users browser. From memory the code is something sort of like this:
Response.ContentType = "application/pdf";
Response.AppendHeader("Content-Disposition","attachment; filename=nameofthefile.pdf");
Currently you are saving your file on the file server, thereby overwriting the same pdf with every request. And probably causing errors if you get two requests for a PDF at the same time.
Use Response to return the PDF (from the memorystream) to the user, and skip the writing of the PDF to a file locally on your server.
The browser will ask the user where the file should be saved. Something like:
Response.ContentType = "Application/pdf";
myMemoryStream.CopyTo(Response.OutputStream);
Also look at the answer from Alun, using content-disposition you can propose a filename to the user.
SOLVED
The error is from the submit operation trying to interpret the response which it can not because it is not in a known format.
I just set window.location to download files and this works fine.
{
xtype:'button',
text: 'Generate PDF',
handler: function () {
window.location = '/AddData.ashx?action=pdf';
}
}
Instead of setting the location you can also do window.open().
Whether the file will be downloaded or opened depends on browser settings.
You do not need to use MemoryStream. Use Response.OutputStream instead. That's what it's there for. No need to use Response.BinaryWrite() or any other call to explicitly write the document either; iTextSharp takes care of writing to the stream when you use Response.OutputStream.
Here's a simple working example:
Response.ContentType = "application/pdf";
Response.AppendHeader(
"Content-Disposition",
"attachment; filename=test.pdf"
);
using (Document document = new Document()) {
PdfWriter.GetInstance(document, Response.OutputStream);
document.Open();
document.Add(new Paragraph("This is a paragraph"));
}
Here's how to add the proper HTTP headers. (getting the prompt to save the file) And if your code is in a web form, (button click handler), add Response.End() to the code example above after the using statement so that the web form's HTML output is not appended the PDF document.

Categories