Exception While Downloading PDF file in asp.net - asp.net

I am downloading a file in asp.net
Here is the code
Response.ContentType = "Application/.pdf";
Response.AppendHeader("Content-Disposition", "attachment; filename="+extractFileName+".pdf");
Response.TransmitFile(extractFilePath);
Response.Flush();
Response.End();
The file is downloading properly but at Response.End(); it throws following exception:
{Unable to evaluate expression because the code is optimized or a native frame is on top of the call stack.}

The provided message is not an exception, but a message indicating that it cannot show you the error due to optimizations performed by the compiler, and due to the current code location.
Try removing the response.End and see if it will allow you to see the error.

There are several issues.
I think the main issue will be that you're using extractFileName for both the name that will be used to open/save the file at the browser, and also as the physical name of the file to transmit. So you are either using a full path for the content-disposition when it needs just a filename... or you are not giving a full path for the transmit.
You are also using an incorrect MIME Type for the PDF, which should be application/pdf
(And you are also include .pdf at the end of the extractFileName, so I presume the variable doesn't already include the extension?)
If extractFileName is the full physical path to the file (including extension), then try replacing...
Response.AppendHeader("Content-Disposition", "attachment; filename="+extractFileName+".pdf");
with...
string contentFileName = System.IO.Path.GetFileName(extractFileName);
Response.AppendHeader("Content-Disposition", "attachment; filename="+contentFileName);

TransmitFile() cannot be used for files outside the directory structure of your website. In that case use another way to write the file to the Response.
Remark:
If the filename contains multiple points (.) or characters like comma (,), some browsers will mess up the filename. Add extra quotes to the filename to avoid problems.
Response.AppendHeader("content-disposition", "attachment; filename=\"" + file + "\";");

Related

Unreadable excel content Epplus

I am making a Post request and receiving the response from an end point, through which i receive the excel content.
I have used this end point before and tried binding a email worker, which works fine. (Conforming end point response is clear).
Now with a different requirement, i need to make the post call to this end point and download the excel file.xlsx file hence generated is corrupted and i excel tries to recover it once the file is downloaded.
Have gone thorugh different threads and tried almost everything.
Nothing seems to work.
try 1:
Response.Clear();
stream.Flush();
stream.Seek(0, SeekOrigin.Begin);
return File(stream, "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet", fileName.Replace("\"", String.Empty));
And while debugging i have made sure to close the response. (Response.End()).
Have even added the explicit headers
Response.AddHeader("content-disposition", "attachment; filename=\"" fileName".xlsx\"");
Response.ContentType = "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet";
Try 2
have explicity written the memoryStream to the response.
Response.BinaryWrite(tgtBytes);
Have ensured Response.Clear before writing to response and making sure of memoryStream.dispose and Response.End.
Have even used. Response.ClearHeaders().
Try - 3.
Instead of MemoryStream, tried with filestream, saving in a file and downloading from the File written. Problem still Persists.
I am getting a binaryStream as response and no encoding in done as it isn't hex value.
Either the stream is corrupted ( which is likely not the case, as i use the end point for different requirements) or the response is corrupted.
how should i check what is the exact cause ??
Please Let me know what else can i try.

PDF file sometime being displayed as garbage

I am having a user who is reporting that files are being displayed as raw data in his browser. He uses Internet Explorer.
The files are being served via a .ashx handler file and it has been working until.
This is the relevant part of my .ashx handler:
context.Response.Clear()
context.Response.AppendHeader("Content-Disposition", "attachment; filename=" + name)
context.Response.AppendHeader("Content-Length", size.ToString)
context.Response.ContentType = "application/pdf"
context.Response.TransmitFile(fullname)
context.Response.Flush()
HttpContext.Current.ApplicationInstance.CompleteRequest()
Can anyone figure something out of this screenshot?
Update: this behaviour appears on Windows 10 when running either IE 11 or Edge and only the second time a file is being opened. It happens for both .pdf and .docx files.
This is the code I use to stream PDFs to a client. It works in IE 11. The main difference is that I am using BinaryWrite which based on your code, you may not want to do..
HttpContext.Current.Response.Clear();
HttpContext.Current.Response.AddHeader("Content-Type", "application/pdf");
HttpContext.Current.Response.AddHeader("Content-Disposition", "inline; filename=" + fileName + ".pdf");
HttpContext.Current.Response.BinaryWrite(bytes);
HttpContext.Current.Response.End();
There might be a solution here
I'll like this as well just in case..
According to this thread, it could be as simple as replacing Response.Close with Response.End (or in your case.. adding)
I finally found the answer myself - it had to do with the HTTP header content-length which i mistakenly submitted with a value exactly 1byte too large.
This caused the strange behavior in only IE/Edge and only Windows 10 as described in the OP.
I had the same problem with an aspx page that transmits file to browser in Page_Load event handler.
My mistake was an absense of
Response.End();
method call. When I added this line the problem has gone.

Prompting user for download, IE sets the filename as the .aspx name ("Would you like to download SomePage.aspx?fileID=12345")

I am at a loss here. I am trying to transmit a file on the local intranet site. When I get a download prompt in IE11, it says:
Do you want to open or save "SomePage.aspx?fileID=12345"? [open] [save] [cancel]
Instead of..
Do you want to open or save "Document.pdf"? [open] [save] [cancel]
It works perfectly fine on Chrome. The file gets downloaded with the correct filename. But for some reason, IE isn't setting the name and instead uses the ASPX name.
The code is rather straightforward:
testFile = New System.IO.FileInfo("\\someshare\somefolder$\Document.pdf")
Response.Clear()
Response.AddHeader("Content-Disposition", "attachment; filename=" & testFile.Name)
Response.AddHeader("Content-Length", testFile.Length.ToString())
Response.ContentType = "application/octet-stream"
Response.TransmitFile(testFile.FullName)
I've tried a number of different header options and the MIME type makes no difference.
Does anyone have a clue why this would be happening?
Notes: Not HTTPS. It is not limited to PDF, same happens with .TIF, .DOC, and every other format I've tested.
EDIT: Have also tried Response.WriteFile as well as Response.BinaryWrite .. same thing each time.
EDIT2: Simplified everything down to a single button on a completely blank page.
You should have quote marks around the file name. See 19.5.1 on http://www.w3.org/Protocols/rfc2616/rfc2616-sec19.html
i.e.
Content-Disposition: attachment; filename="fname.ext"
so...
Response.AddHeader("Content-Disposition", String.Format("attachment; filename=""{0}""", testFile.Name))
Unfortunately I have not been able to test if this solves your issue as I don't have access to IE11 at the moment.
So I know this question is older, but the solution I finally came up with to this problem is to add the following two lines to my code.
Response.SuppressContent = True
and
HttpContext.Current.ApplicationInstance.CompleteRequest()
You have said in previous comments that you have tried the CompleteRequest command to no avail.
As a note, I am not 100% certain to the logistics of the Response.SuppressContent() command.
The documentation says that it indicates "whether to send HTTP content to the client". This seems counter intuitive to the process of sending the request body back to the client, however, it appears to only suppress the parts of the response that include any HTML.
It seems that the partial or incomplete HTML is what causes the filename to appear as the page name regardless of the headers set and sent. Stripping this out should cause the file to download properly.
Interestingly, this solution is actually born out of a secondary issue where once I was able to export the file using ClosedXML, i was receiving messages when opening the document that there were errors than excel would try to fix.
Response.SuppressContent actually fixed that as well. Hope this helps or at least points you in the right direction.

How do I send a binary blob to a client browser?

Pardon the dumb newbie question here; web programming isn't my forte... (blush)
I have an aspx page running on a web server. I have a blob (byte array) containing any kind of binary file, plus a file name.
I would like to push this file to be downloaded through the browser onto the client, and opened using whatever application is default for this file type. I really don't want to save the blob as a file on the server; that will leave a terrible housekeeping mess that I just don't want to think about.
I did try googling this question, but I guess I'm using the wrong keywords.
This really should be obvious how to do it, but I'm having no joy.
What is the trick?
Thanks!
Response.BinaryWrite(byteArray);
You should also set the content type
Response.ContentType = "application/pdf";
But that will be based on your file type.
And the file name (and everything together) is done like this
Response.AddHeader("content-disposition",
String.Format("attachment;filename={0}", fileName));
Response.ContentType = "application/pdf";
Response.BinaryWrite(byteArray);
First, you have to know the mime type. Once you know that, you can set the Response.ContentType property. After that, just use Response.BinaryWrite(). If you don't first set the ContentType property, the client will have almost no chance of opening the file correctly.

Zip Folder is always corrupted after downloaded

For some reason when I download a zip folder from my server's folder it is always corrupted. Here is the code:
protected void gvFiles_RowCommand(object sender, System.Web.UI.WebControls.GridViewCommandEventArgs e)
{
string fileUrl = String.Empty;
if(e.CommandName.Equals("DownloadFile"))
{
fileUrl = e.CommandArgument as String;
string fileName = Path.GetFileName(fileUrl);
Response.AppendHeader("content-disposition",
"attachment; filename=" + fileName);
Response.ContentType = "application/zip";
Response.WriteFile(fileUrl);
Response.End();
}
}
And here is how the GridView is populated:
private void BindData()
{
List<SampleFile> files = new List<SampleFile>();
for(int i=1;i<=3;i++)
{
SampleFile sampleFile = new SampleFile();
sampleFile.Name = "File " + i;
sampleFile.Url = Server.MapPath("~/Files/File"+i+".txt");
files.Add(sampleFile);
}
SampleFile file = new SampleFile();
file.Name = "Zip File";
file.Url = Server.MapPath("~/Files/WebSiteNestedMasters.zip");
files.Add(file);
gvFiles.DataSource = files;
gvFiles.DataBind();
}
I don't know asp.net at all, but this is pretty commonly a result of doing the download in a text mode instead of binary mode. Line ending characters get converted from \r\n to \n or vice versa, and everything goes nuts.
As #lassevk suggested you should download the corrupted zip file and compare it with the original file on the server. Are both the same length? Use a hex editor to inspect the contents of the file. In this related thread you are saying that if you point the browser directly to the zip file it is also corrupted, meaning that the problem is probably not related to the headers but something wrong with IIS. Are you using some third party ISAPI extensions that could modify the file?
Assuming that you need to do this: (e.g. you are unable to provide a direct link)
<a href='<% Eval("Url")) %>'>download</a>
I'll first make an observation that having a RowCommand handler start to return a file isn't the way to do this. Create some sort of download link to a different page. Separate file downloading from the rest of the page containing the grid.
now ...
You've got the basics about right, but like a comment in this CodeProject tutorial you're soon going to run into issues.
Where the above code sample falls
down:
not responsive to user
the code will keep going and you'll have no
idea if the user actually downloaded
the file (it may not matter to you)
won't work with all browsers
cannot resume a download
doesn't show progress
larger files will use more server memory and take longer to stream
and a lot of downloads will mean the server is going to take a resource hit
whereas you might want ..
works just like a clicked download (ie using get, not post)
works in all browsers on all platforms in the way the user expects
(ie filename hint works on things like
IE for Mac or Netscape 4.1).
show download progress
resumable downloads
tracking all downloads and knowing when downloads complete
looks like a file, even if it isn't
expiration on url.
allows for high concurrent # of downloads for any size of file
Although written in VB .net1.1 the article Tracking and Resuming Large File Downloads in ASP.NET [devx] is far better at explaining how to do it correctly.
Easy code is easy but doesn't always work, and efficiently streaming files to users 100% of the time takes a little more effort than setting a content header and shoveling some bits down the wire.
First, verify that the contents of the file actually looks like a zip file. You can do that simply by dropping the file into notepad, and looking at the contents. If the file starts with PK and some funny characters, it might be a zip file. If it contains HTML, that might be a clue as to why it is going wrong.
Looking at your code, it struck me that you're passing the url to the file to Response.WriteFile. Does Response.WriteFile handle url's or does it use local filenames? Perhaps everything up to Response.WriteFile works, and thus the right headers are sent, etc. but then the code crashes with an exception, which might make your "zip file" contain a HTML error message.
Edit: Ok, first problem-solving step completed. File looks like a zip file in notepad, not a HTML error message.
Next step, since the file resides on the server, try writing an url directly to the file, instead of going through your application. Does that work?
If not, try a different zip program (which one are you using by the way?).
As an example of why you should try the file directly and different unzipping programs. FinalBuilder produces zip files that PowerArchiver complains about, but 7zip does not, so there might be something wrong with either the file or your program, or possibly even both.
But verify that the files are correct, can be opened, both if you don't download them at all, and check what happens if you download them directly outside of your application.
Edit: Ok, you've verified that the file won't open even if you download it directly from your server.
How about opening the file in just explorer, bypassing the web server altogether? For instance, since it looks like you have the file locally, try just navigating to the right folder and opening the file directly. Does that work?
Here is the updated code:
fileUrl = e.CommandArgument as String;
string fileName = Path.GetFileName(fileUrl);
FileStream fs = new FileStream(fileUrl, FileMode.Open);
byte[] buffer = new byte[fs.Length];
fs.Read(buffer, 0, (int) fs.Length);
fs.Close();
Response.Clear();
Response.AppendHeader("content-disposition",
"attachment; filename=" + fileName);
Response.ContentType = "application/octet-stream";
Response.AppendHeader("content-length", buffer.Length.ToString());
Response.BinaryWrite(buffer);
Response.Flush();
Response.End();
Here is the fiddler stats:
HTTP/1.1 200 OK
Server: ASP.NET Development Server/8.0.0.0
Date: Wed, 17 Dec 2008 22:22:05 GMT
X-AspNet-Version: 2.0.50727
Content-Disposition: attachment; filename=MyZipFolder.zip
Content-Length: 148
Cache-Control: private
Content-Type: application/x-zip-compressed
Connection: Close
I just tried the same code with the .docx file and same result (The file is corrupted): Here is the code:
if(e.CommandName.Equals("DownloadFile"))
{
fileUrl = e.CommandArgument as String;
string fileName = Path.GetFileName(fileUrl);
FileInfo info = new FileInfo(fileUrl);
Response.Clear();
Response.ClearContent();
Response.ClearHeaders();
Response.Buffer = true;
Response.AppendHeader("Content-Length",info.Length.ToString());
Response.ContentType = GetContentType(fileUrl);
Response.AppendHeader("Content-Disposition:", "attachment; filename=" + fileName);
Response.TransmitFile(fileUrl);
Response.Flush();
Response.End();
}

Resources