ASP.NET MVC cannot stream files - c#

I have a ASP.NET MVC 4 site that creates an excel file using OPEN XML SDK. I simply point the hyperlink to the proper controller and it generates the OPEN XML excel document and writes the stream to response header and done. In IE 9 and Chrome this works fine. File gets downloaded with the given file name and proper contents. However, just recently I upgraded my browser to IE 10 and now instead of downloading the file and opening up in excel I get the error that could not open 'URI'. When I click ok it gives another error: Microsoft Excel cannot access the file 'URI'. There are several possible reasons:
I don't understand why this would work in IE 9 and chrome and not in IE 10. I debugged the response headers with fiddlers and it has the proper content type, and content length set:
Content Type: application/vnd.openxmlformats-officedocument.spreadsheetml.sheet
Content Disposition: attachment; filename=result.xlsx
Content length: 1232
Is there something that I am missing?
Code snippet: This all is part of
public override void ExecuteResult(ControllerContext context)
{
...
....
..
extention = "xlsx";
response.ContentType = "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet";
response.AddHeader("Content-Disposition",
String.Format("attachment; filename={0}.{1}", fileName, extention));
response.AddHeader("Content-Length", mem.Length.ToString());
mem.Seek(0, SeekOrigin.Begin); // Go back to the begining.
mem.CopyTo(response.OutputStream);
context.HttpContext.ApplicationInstance.CompleteRequest();
}

As a workaround, Controller.File works for me with ASP.NET MVC 4 and IE 10:
public class DownloadController : Controller
{
public ActionResult GetFile()
{
...
mem.Position = 0;
return File(
mem,
"application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",
"result.xlsx");
}
}
EDIT
So I have been browsing the MVC source code at CodePlex and found a few implementation details that differ from your code snippet:
Content-Length header is never set
Instead of calling Stream.CopyTo, they use a simple Stream.Read, Stream.Write loop with buffer size of 0x1000
When setting Content-Disposition header, they check whether file download name contains UTF-8 chars, and if so, encode them according to RFC 2231. See ContentDispositionUtil.GetHeaderValue
context.HttpContext.ApplicationInstance.CompleteRequest() is never called
Now you could try applying these changes one by one and see which one makes it work with IE 10.

I guess it's an IE10 bug. But maybe you still can work around it.
Based on this post and a few others.
Please check that:
Both full URI and the filename of Content Disposition header do not contains special symbols and that their lengths are less than 105. Just use regular A-Za-z0-9 symbols for instance.
Try to add "X-UA-Compatible" HTTP header with "IE=9" value.

try these MIME types:-
for old version:-
Response.ContentType = "application/vnd.ms-excel";
Response.AppendHeader("content-disposition", "attachment; filename=myfile.xls");
for 2007:-
Response.ContentType = "application/application/vnd.openxmlformats-officedocument.spreadsheetml.sheet";
Response.AppendHeader("content-disposition", "attachment; filename=result.xlsx");
for csv files which you need to open in excel is:-
Response.AddHeader "Content-Disposition", "Attachment;Filename=myfile.csv"
in last you can try:-
Response.ContentType = "application/octet-stream";
Response.AppendHeader("content-disposition", "attachment; filename=result.xlsx");
thanks

Related

What is the correct Excel Application type? [duplicate]

I use CarlosAG-Dll which creates a XML-Excel-file for me (inside a MemoryStream).
Response.ContentType = "application/vnd.ms-excel";
Response.AppendHeader("content-disposition", "myfile.xml");
memory.WriteTo(Response.OutputStream);
My Problem here is, that I get at client side a myfile.xls (IE) or a myfile.xml.xls (FF) and therefore get an annoying security warning from excel.
I tried it as well with application/vnd.openxmlformats-officedocument.spreadsheetml.sheet (xlsx) but then it won't even open.
So I need to either cut the .xml and send it as vnd.ms-excel (how?) or take another MIME-type (but which one?).
edit: I found a bug description here
I wonder if this is still open and why?
Use like this
Response.ContentType = "application/vnd.ms-excel";
Response.AppendHeader("content-disposition", "attachment; filename=myfile.xls");
For Excel 2007 and above the MIME type differs
Response.ContentType = "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet";
Response.AppendHeader("content-disposition", "attachment; filename=myfile.xlsx");
See list of MIME types
Office 2007 File Format MIME Types
EDIT:
If the content is not a native Excel file format, but is instead a
text based format (such as CSV, TXT, XML), then the web site can add
the following HTTP header to their GET response to tell IE to use an
alternate name, and in the name you can set the extension to the right
content type:
Response.AddHeader "Content-Disposition", "Attachment;Filename=myfile.csv"
For more details see this link
If your document is an Excel Xml 2003 document, you should use the text/xml content type.
Response.ContentType = "text/xml";
Do not specifiy content-disposition.
This technichs works great with Handler, not with WebForm.
The security warning is NOT about the MIME type - it is a client-side security setting you can't disable from the server side !
Another point - change Response.AppendHeader("content-disposition", "myfile.xml"); to:
Response.AppendHeader("content-disposition", "attachment; filename=myfile.xlsx");
OR
Response.AppendHeader("content-disposition", "inline; filename=myfile.xlsx");
For reference see http://www.ietf.org/rfc/rfc2183.txt
EDIT - as per comment:
IF the format is not XLSX (Excel 2007 and up) then use myfile.xls in the above code.

Download Document in the right format without MIME

I have got this WebService that allows uploading/downloading any docs (mostly .docx, .doc, .pdf) and all it returns is byte[] when querying for downloading.
I have written this code
string ContractGUID = dtContract.Rows[0]["ContractGUID"].ToString();
//Get Bytes from WebService
byte[] fileData = BLL.Contract.GetDocument(new Guid(ContractGUID));
Response.Clear();
Response.BinaryWrite(fileData);
Response.AddHeader("Content-Disposition", "Attachment");
Response.Flush();
The other methods that the WebService exposed are GetDocumentName and GetDocumentLen
Is it possible to determine the Mime-Type or force the browser to download it in the right format? Currently it is downloading as .htm in Chrome and when open, I see funny characters. Any better advice?
Thanks.
No, it's not possible to force the browser to download in the right format without you telling it via the Content-Type header.
Response.ContentType = "application/pdf"; //or whatever appropriate
If the web service exposes a GetDocumentName() method you can probably infer the appropriate format by looking at the name, assuming the name has a file extension. This, obviously, is not bullet proof since you can change the extension of a file to anything you want.
Another alternative would be to try and guess the file format by peeking at the first bytes. For example, if the first 4 bytes of the file are 25 50 44 46 then it's very likely that this is a PDF file. On this website, they have a pretty extensive list.
Here's the list of possible content-type headers.
I think, the browser does it through filename.
e.g.:
response.Clear();
response.AddHeader("Content-Disposition", "attachment; filename=" + dbFile.filename.Replace(" ", "_"));
response.AddHeader("Content-Length", dbFile.data.Length.ToString());
response.ContentType = "application/octet-stream";
response.OutputStream.Write(dbFile.data, 0, dbFile.data.Length);
response.End();
dbFile.filename is a string
dbFile.data is a byte[]

Download an Excel file

I have read some past posts here on how to download a Excel file from a website. So, I have setup the below code:
string path = MapPath(fname);
string name = Path.GetFileName(path);
string ext = Path.GetExtension(path);
string type = "application/vnd.ms-excel";
if (forceDownload)
{
Response.AppendHeader("content-disposition",
"attachment; filename=" + name);
}
if (type != "")
{
Response.ContentType = type;
Response.WriteFile(path);
Response.End();
}
However, I get no download dialog box.
I try this both in IE 8 and FireFox 10.0.2.
The file is there, it's not locked, and it's not set to read only.
I'm not sure were I went wrong.
According to this link, you need to add this line:
strFileName = Path.GetFileName(path);
Response.TransmitFile( Server.MapPath(strFileName) );
This will cause a Open / Save As dialog box to pop up with the filename of SailBig.jpg as the default filename preset.
This of course assumes you're feeding a file that already exists. If you need to feed dynamically generated - say an image [or any file] that was generated in memory - you can use Response.BinaryWrite() to stream a byte array or write the output directly in Response.OutputStream.
EDIT:
Microsoft's MSDN site has a detailed explanation about File Downloading. It includes both samples for Java and .Net applications, the concept is the same:
Get the response.
With the response:
Set the content type to "APPLICATION/OCTET-STREAM" (it means there's no application to open the file).
Set the header to "Content-Disposition", "attachment; filename=\"" + + "\"".
Write the file content into the response.
Close the response.
So, looking at the MSDN ASP.Net file download, you're lacking the 2.3 step. You're just writing the file name to the response.
// transfer the file byte-by-byte to the response object
System.IO.FileInfo fileToDownload = new
System.IO.FileInfo("C:\\downloadJSP\\DownloadConv\\myFile.txt");
Response.Flush();
Response.WriteFile(fileToDownload.FullName);
With this example you will download your file successfully, of course if you can get the file with no problems :).
EDIT 2:
The HTML component used to download any file must be a regular HTML Request. Any ajax request to download a file won't work. Microsoft explains that here. And the main quote:
Its impossible to attach an event before and after a download through javascript. Browser doesn't allow this type of events for security reasons.
You need to send this before the file attachment header:
Response.ContentType = "application/vnd.ms-excel"
See: Export data to excel file from Classic ASP failing
Try adding such HTTP headers
Content-Type: application/force-download
Content-Type: application/vnd.ms-excel
Content-Type: application/download

MIME-Type for Excel XML (ASP.NET 3.5)

I use CarlosAG-Dll which creates a XML-Excel-file for me (inside a MemoryStream).
Response.ContentType = "application/vnd.ms-excel";
Response.AppendHeader("content-disposition", "myfile.xml");
memory.WriteTo(Response.OutputStream);
My Problem here is, that I get at client side a myfile.xls (IE) or a myfile.xml.xls (FF) and therefore get an annoying security warning from excel.
I tried it as well with application/vnd.openxmlformats-officedocument.spreadsheetml.sheet (xlsx) but then it won't even open.
So I need to either cut the .xml and send it as vnd.ms-excel (how?) or take another MIME-type (but which one?).
edit: I found a bug description here
I wonder if this is still open and why?
Use like this
Response.ContentType = "application/vnd.ms-excel";
Response.AppendHeader("content-disposition", "attachment; filename=myfile.xls");
For Excel 2007 and above the MIME type differs
Response.ContentType = "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet";
Response.AppendHeader("content-disposition", "attachment; filename=myfile.xlsx");
See list of MIME types
Office 2007 File Format MIME Types
EDIT:
If the content is not a native Excel file format, but is instead a
text based format (such as CSV, TXT, XML), then the web site can add
the following HTTP header to their GET response to tell IE to use an
alternate name, and in the name you can set the extension to the right
content type:
Response.AddHeader "Content-Disposition", "Attachment;Filename=myfile.csv"
For more details see this link
If your document is an Excel Xml 2003 document, you should use the text/xml content type.
Response.ContentType = "text/xml";
Do not specifiy content-disposition.
This technichs works great with Handler, not with WebForm.
The security warning is NOT about the MIME type - it is a client-side security setting you can't disable from the server side !
Another point - change Response.AppendHeader("content-disposition", "myfile.xml"); to:
Response.AppendHeader("content-disposition", "attachment; filename=myfile.xlsx");
OR
Response.AppendHeader("content-disposition", "inline; filename=myfile.xlsx");
For reference see http://www.ietf.org/rfc/rfc2183.txt
EDIT - as per comment:
IF the format is not XLSX (Excel 2007 and up) then use myfile.xls in the above code.

Change name of file sent to client?

I have a webpage that pulls information from a database, converts it to .csv format, and writes the file to the HTTPResponse.
string csv = GetCSV();
Response.Clear();
Response.ContentType = "text/csv";
Response.Write(csv);
This works fine, and the file is sent to the client with no problems. However, when the file is sent to the client, the name of the current page is used, instead of a more friendly name (like "data.csv").
My question is, how can I change the name of the file that is written to the output stream without writing the file to disk and redirecting the client to the file's url?
EDIT: Thanks for the responses guys. I got 4 of the same response, so I just chose the first one as the answer.
I believe this will work for you.
Response.AddHeader("content-disposition", "attachment; filename=NewFileName.csv");
You just need to set the Content-Disposition header
Content-Disposition: attachment; filename=data.csv
This Microsoft Support article has some good information
How To Raise a "File Download" Dialog Box for a Known MIME Type
Add a "Content-Disposition" header with the value "attachment; filename=filename.csv".
Response.AddHeader("content-disposition", "attachment; filename=File.doc")

Categories