How to display PDF attachment in IE6 - asp.net

I have an ASP.net application which returns a binary PDF file (stored from the database, which was previously uploaded) to the client.
The code I have works fine for all browsers, except for internet explorer 6 (story of my life!). In IE6, when a user clicks open, Adobe reports the error: "There was an error opening this document. The file cannot be found."
When the user clicks save, the PDF saves fine and can be opened by double clicking it. I am stumped. Google has given suggestions of caching (setting cachecontrol to private etc) and I have tried all of those but nothing has worked.
The wierd(er) behaviour is when I generate a PDF in my ASP .net server layer (using NFop) from scratch, IE will open it fine (using the SAME code!).
Here is my code for sending the binary data across the wire:
// Firefox doesn't like spaces in filenames.
filename = filename.Replace(" ", "_");
string extension = Path.GetExtension(filename);
string contentType;
switch (extension)
{
case "pdf":
contentType = "application/pdf";
break;
default:
contentType = "application/x-unknown";
break;
}
context.Response.Clear();
context.Response.AddHeader("content-disposition", "attachment;filename=" + filename);
context.Response.Charset = "";
context.Response.ContentType = contentType;
context.Response.BinaryWrite(data);
context.Response.Flush();
Here are application versions:
ASP .net 3.5
IE6.0.2900.2180.xpsp_s
List item
p2_gdr.091208-2028
Adobe Reader version 8.0.0
Windows XP SP 2
SQL Server 2008
Any help/suggestions would be much appreciated. Thanks :)
EDIT:
I have plugged in Fiddler to view the headers and sure enough it does appear to be a caching issue. grrr!
When my NFop PDF (the one that works) is uploaded, it is sending cache-control = private.
When my attachment PDF (the one that doesn't work) is uploaded, it sends no-cache.
I have looked in the Response object and both appear to have the same headers when I call context.Response.Flush().
Still stumped!
SOLVED:
Somewhere in our framework was a rogue method which was being invoked using reflection:
///
/// Sets the expiratoin of the request and force no cache
///
protected void SetCacheExpiration(HttpContext context)
{
//sets the cache to expire immediately
context.Response.Cache.SetCacheability(HttpCacheability.NoCache);
context.Response.Cache.SetSlidingExpiration(true);
context.Response.Cache.SetExpires(DateTime.Now);
context.Response.Cache.SetMaxAge(new TimeSpan(0, 0, 0));
context.Response.Cache.SetNoStore();
context.Response.Cache.SetAllowResponseInBrowserHistory(false);
context.Response.Cache.SetValidUntilExpires(false);
context.Response.Cache.SetRevalidation(HttpCacheRevalidation.AllCaches);
}
Thanks for your help, caching! It is interesting that the only browser that actually didn't cache the download (when opened) was IE6.

Here the method I've used before to render in-browser PDFs for IE6. Again... this was for a project where we showed the PDF in the browser, but it should serve you well for a PDF that's shown in the reader.

Somewhere in our framework was a rogue method which was being invoked using reflection:
/// <summary>
/// Sets the expiratoin of the request and force no cache
/// </summary>
protected void SetCacheExpiration(HttpContext context)
{
//sets the cache to expire immediately
context.Response.Cache.SetCacheability(HttpCacheability.NoCache);
context.Response.Cache.SetSlidingExpiration(true);
context.Response.Cache.SetExpires(DateTime.Now);
context.Response.Cache.SetMaxAge(new TimeSpan(0, 0, 0));
context.Response.Cache.SetNoStore();
context.Response.Cache.SetAllowResponseInBrowserHistory(false);
context.Response.Cache.SetValidUntilExpires(false);
context.Response.Cache.SetRevalidation(HttpCacheRevalidation.AllCaches);
}
Thanks for your help, caching! It is interesting that the only browser that actually didn't cache the download (when opened) was IE6.

Related

Asp.Net 6.0 Redirect user to a URL containing json content and start download

I have a scenario where the user passes a fileName to download.
We don't download the file on the server and stream back to the user because of bandwidth restrictions
We get the file path to download, and redirect to the location where the json file would be hosted
[Route("[controller]/DownloadJsonFile")]
public async Task DownloadJsonFile(string fileName)
{
//Get the file name
string fileToDownload = "https://hostedfilelocation/....test.json"
Response.Redirect(fileToDownload);
}
Currently, this method ends up rendering the Json content on the browser.
Is there a way so that the browser can start automatically downloading the file?
That way it wouldn't take super long to render the file on the browser.
P.S. If the file is of type zip or gzip, it is not rendered on the browser but rather is automatically downloaded.
The application is a .Net 6 Asp.Net MVC application
I have tried the below code but the behavior is the same but it renders json on the browser instead of downloading it.
string fileToDownload = "https://hostedfilelocation/....test.json"
HttpResponse response = HttpContext.Response;
response.Clear();
response.ContentType = "application/octet-stream";
response.Headers.Add("Content-Disposition", "attachment; filename=" + fileName);
Response.Redirect(fileToDownload);
The approaches mentioned in this blog post are all mentioning rendering the file in an iframe but I want the download happen on the client side.
Download File via browser redirect
If you want to download it directly, add the download attribute:
<a class='download-file-link' target='_blank' href='DownloadJsonFile' download="somefilename">

Avoiding Protected view when opening streamed Excel documents

We have an ASP.NET application which dynamically generates Excel documents and streams them to the client, using Response.WriteFile, see code below. Note that the document is deleted once the file has been written to the client. Thus, no documents are ever left on the server.
However, my client's users has now all upgraded to Office 2010, and now the documents will open in "Protected View". In order to edit the document, the user has to click "Enable editing" first. This is considered unacceptable for the users.
The reason that this happens is that streamed documents are placed in the Temporary Internet files, and this is considered a "potentially unsafe location". And documents in such locations are opened in protected view. I am just hoping there is some way to work around this.
Theoretically, I could place the document in a folder which is accessible from the client, and redirect to the document.
This solution is not an option, however. Firstly, since the document would be left on the server, it could be accessible for other users, which is a problem since the documents may contain confidential data.
There are other reasons why this is not a vialable option.
An other theoretical workaround would be to ask all users to disable the setting "Enable protected view for files located in potentially unsafe locations". Naturally, this is not an option either.
So, in short, is there anyway to avoid the documents to be opened in "Protected view" while using the streaming technique described below?
Response.Buffer = true;
Response.Clear();
Response.AddHeader("Pragma", "no-cache");
Response.Expires = 0;
Response.AddHeader("Content-Type", contentType);
Response.AddHeader("Content-Disposition", "attachment; filename=" + proposedFilename);
Response.WriteFile(dstFullPathName);
Response.Flush();
Response.Close();
File.Delete(dstFullPathName);
HttpContext.Current.ApplicationInstance.CompleteRequest();

Updating a page before initiating a download?

I've got a page that allows users to enter search criteria and then display matching records. It also has a download button to enable the user to download matching records.
How can I code it so that clicking on "Download" will first refresh the record display before downloading the data?
This is the code that I'm using for the download:
Response.ClearContent();
Response.ClearHeaders();
using (MemoryStream outputStream = new MemoryStream())
{
// some details elided...
outputStream.Write(documentData, 0, documentData.Count());
string fileName = GenerateFileName();
Response.AppendHeader("content-disposition", String.Format("attachment; filename={0}", fileName));
outputStream.Flush();
outputStream.WriteTo(Response.OutputStream);
}
Response.Flush();
Response.Close();
Only one response you can send back to the browser, ether you update the data, ether you send the new header to start the download.
To make both of them you need to change your steps probably using some javascript and/or ajax call.
How HTTP protocol works: http://www.w3.org/Protocols/rfc2616/rfc2616-sec1.html
Construct a javascript method that first updates the page via AJAX, then proceeds to make a non-AJAX request to download the file. As Aristos says, this cannot be done in a single request. A different solution could be to download the file first (non-ajax), then refresh the page without ajax. Normally, javascript code cannot be executed correctly after a new non-ajax request is made, but if it only downloads a file, I think the code might continue its execution to post the next request.

Why LiveId Web Auth requires to confirm cookie removal with IMAGE/GIF response?

In LiveId Web Auth scenario, when client application receive "clearcookie" request, it is responsible for clearing the authorization cookies and should confirm success by returning any GIF image through http. Using reference implementation of liveid web auth in asp.net-mvc looks like:
if (Request["action"]=="clearcookie")
{
string contentType;
byte[] content;
wll.GetClearCookieResponse(out contentType, out content);
return this.File(content, contentType);
}
Where wll.GetClearCookieResponse is implemented as:
public void GetClearCookieResponse(out string type, out byte[] content)
{
const string gif =
"R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAEALAAAAAABAAEAAAIBTAA7";
type = "image/gif";
content = Convert.FromBase64String(gif);
}
So the GetClearCookieResponse method creates byte[] array containg tiny hardcoded GIF.
Is there any particular reason why responding with GIF is required? Why not just plain text ("OK") or JSON?
Are there any other (than LiveId) protocols using returning GIF as a response? I'm asking because I want to know if there is any reason to adopt this solution in projects requiring similar scenarios of communication.
When a user signs out of Windows Live or a Windows Live pplication, a best-effort attempt is made to sign the user out from all other Windows Live applications the user might be signed in to. This is done by calling the handler page for each application with 'action' parameter set to 'clearcookie' in the query tring. The application handler is then responsible for clearing any cookies or data associated with the login. After successfully signing the user out, the handler should return a GIF (any GIF) as response to the action=clearcookie query.
This function returns an appropriate content type and body response that the application handler can return to signify a successful sign-out from the application.
Your code should only return the image (.gif) as specified, and nothing else. An extra byte will trigger an error (malformed image).
I suppose it could be any type of expected response and suspect they chose a GIF because it would cause a browser to promptly hang up the connection when received.

IIS7 downloading file length

I've following code for file download:
FileInfo fileInfo = new FileInfo(filePath);
context.Response.Clear();
context.Response.ContentType = "application/octet-stream";
context.Response.AddHeader("Content-Disposition", "attachment; filename=" + System.IO.Path.GetFileName(filePath));
context.Response.AddHeader("Content-Length", fileInfo.Length.ToString());
context.Response.WriteFile(filePath);
context.Response.End();
When I run it on my local IIS6 it works fine. Web browser (tested on IE8, Firefox 3.5.2, Opera 10) shows file length before I start download the file.
When I run this code on remote IIS7, web browser doesn't shows file length. File length is unknown.
Why I don't get file length when this code runs under IIS7?
Use Fiddler to check what is actually sent. My guess is you are getting chunked encoding as a result of buffering being set to false on the IIS7 server.
BTW, drop the Response.End call its quite a traumatic thing to do and is unnecessary (for that matter so is the call to Clear).
Edit
Strictly speaking when streaming content with chunked encoding (which is desirable in your scenario) the Content-Length header ought not be present (see RFC2616 Section 4.4.) It seems to me that IIS7 takes it upon itself to enforce this. In fact I've had a Classic-ASP scenario in which IIS7 throws an error when COM code tries to add a Content-Length header when buffering is off.
This is really annoying because despite what the committee in the ivory towers would like, this header give the end user a very useful piece of info.
Thanks for this post.... I got it working for IE with the first line.
public void WriteCSV(string strData) {
//Required for IIs7 WS2008R2 fix
Response.ClearHeaders();
Response.Clear();
Response.Buffer = true;
Response.ContentType = "application/csv";
Response.AddHeader("Content-Disposition", "attachment;filename=report.csv");
Response.Write(strData);
Response.Flush();
Response.End();
}

Resources