.net File Download on Mac only get .JPEG appended - c#

I've got a legacy app that allows upload and download of files. The files are stored on disc the files names in a SQL database. To allow duplicate files names from the users, the database store the user original file name and a unique name. The files are displayed in a .NET repeater with the command argument supplying both files names (original and unique). When the file is downloaded the code below serves up the file to the user with the original name.
All works fine on PC with Chrome, IE, FFox. For Mac user, they get FileName.ext.jpeg when they should be getting just FileName.ext
I'm not very well versed in Mac stuff. Is there something I can do to ContentType or Content-Dispositon to fix this for the few Mac users and not impact my large PC user base?
Here is the code to rename the file stored on the server with the original name:
LinkButton btn = (LinkButton)(sender);
string sURL = "";
string sFileName = btn.CommandArgument;
string sOriginalFileName = sFileName.Substring(0, sFileName.LastIndexOf("~"));
string sServerFileName = sFileName.Substring(sFileName.LastIndexOf("~") + 1); ;
sURL = sResourceRoot + "\\" + sServerFileName;
Response.ContentType = "image/jpeg";
Response.AppendHeader("Content-Disposition", "attachment; filename=" + sOriginalFileName);
Response.TransmitFile(Server.MapPath(#"~/" + sURL));
Response.End();

Generally, you should quote your filename in the Content-Disposition header -- see here. Note also that unexpected filename characters could play a role in your issue. It's probably worth using the built-in .NET ContentDispositionHeaderValue class to help create your header.
Try this - it should also be safe for all the other browsers you list.
Response.Content.Headers.ContentDisposition = new ContentDispositionHeaderValue("attachment") { FileName = sOriginalFileName };

Related

Why opening a file through Action in ASP.NET MVC application works in IE and Firefox but not in chrome?

I am trying to open a file in View instead of downloading it.The code works fine in IE and Firefox but it downloads the file in Chrome instead of opening it.
Here is my code.
//OpenWord Action
string filePath = #"G:\WordDemo\DocXExample.doc";
var doc = DocX.Create(fileName)
doc.InsertParagraph("This is my first paragraph"+person.FirstName+" "+person.LastName);
doc.Save();
string fileName = "DocXExample.doc";
byte[] fileData = System.IO.File.ReadAllBytes(filePath);
string contentType = MimeMapping.GetMimeMapping(filePath);
string mimeType = "application/msword";
Response.AppendHeader("Content-Disposition", "inline; filename=" + fileName);
return File(fileData, mimeType);
Any Help and Suggestions are welcome.
It does not work consistently across devices and clients cos it is dependent on plugins installed for the client.
Try this.
Host the word document in your site so it is available for download via say http://www.example.com/path/mydocument.doc
In your View add this iframe
<iframe src="http://docs.google.com/gview?url=http://www.example.com/path/mydocument.doc&embedded=true"></iframe>

Prompt user to save/open file in ASP.NET C#

It shouldn't be this hard to find out how to do this. Basically I'm trying to take a string and let the client save it when they click a button. It should pop up with a Save/Open dialog. No extra bells and whistles or anything. It's not rocket science, (or so I would've thought).
There seems to be a ton of different ways, (StreamWriter, HttpResponse, etc.), but none of the examples I've been able to find work properly or explain what's going on. Thanks in advance.
An example one of the many blocks of code I've found...
(This is just an example, feel free to not base your answer around this.)
String FileName = "FileName.txt";
String FilePath = "C:/...."; //Replace this
System.Web.HttpResponse response = System.Web.HttpContext.Current.Response;
response.ClearContent();
response.Clear();
response.ContentType = "text/plain";
response.AddHeader("Content-Disposition", "attachment; filename=" + FileName + ";");
response.TransmitFile(FilePath);
response.Flush();
response.End();
Line 2 says to replace that string. How? This code was advertised as bringing up a dialog. I shouldn't be having to set a path in the code, right?
EDIT: Final Outcome (Edited again, Delete has to come before End();)
string FilePath = Server.MapPath("~/Temp/");
string FileName = "test.txt";
// Creates the file on server
File.WriteAllText(FilePath + FileName, "hello");
// Prompts user to save file
System.Web.HttpResponse response = System.Web.HttpContext.Current.Response;
response.ClearContent();
response.Clear();
response.ContentType = "text/plain";
response.AddHeader("Content-Disposition", "attachment; filename=" + FileName + ";");
response.TransmitFile(FilePath + FileName);
response.Flush();
// Deletes the file on server
File.Delete(FilePath + FileName);
response.End();
Line 2 (FilePath) indicates the path to the file on the server
Line 8:
response.TransmitFile(FilePath);
Transmits that specific file to the client and THAT is what pops the save dialog.
If you don't transmit the file, I'm not sure if the dialog will pop up at all (even though you set a header)
Anyways, I think line 8 should read:
response.TransmitFile(FilePath + FileName);
There will be a default dialog box by browser, if it will find Response as some file. If you want browser to display that default dialog box, all you need to do is send response to browser as file, which you can do in number of ways:
If it is a static file,
best way is to just mention path of file in anchor tag's href.(obviously if you don't have security concern)
Just out along with your response, the way it is done in your example.
Other ways you can refer here 4 ways to send pdf from asp.net
If it is a dynamic file which you need to generate at run time, you can do a trick, generate the file from filestream, put it in some temporary folder at server, read it back as a static file as mentioned above.
Just use this code it should work to prompt the user to open a dialog for opening or saving the file on the system ....
byte[] bytesPDF = System.IO.File.ReadAllBytes(#"C:\sample.pdf");
if (bytesPDF != null)
{
Response.AddHeader("content-disposition", "attachment;filename= DownloadSample.pdf");
Response.ContentType = "application/octectstream";
Response.BinaryWrite(bytesPDF);
Response.End();
}
FilePath is supposed to point to the file you want to send to the client. This is the path on the server.

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

Any possible way to programmatically save to another folder other than the designated downloads folder?

I'm developing a ASP.NET Web application in which a table is converted to an excel spreadsheet. I would like to give the option to the user to save somewhere else than the downloads section. I realize that is a good likelihood that this is prohibited, but maybe there is some sort of class/mechanism facilitated by ASP.net framework.
Here is my current code:
protected void saveDataButton_Click(Object sender, EventArgs e)
{
SaveFileDialog browser = new SaveFileDialog();
string fileName;
if (browser.ShowDialog() == DialogResult.OK)
{
fileName = browser.FileName;
}
else
return;
DataTable table = (DataTable)Session["tableData"];
HttpContext context = HttpContext.Current;
context.Response.Clear();
context.Response.ContentType = "text/csv";
context.Response.AppendHeader("Content-Disposition", "attachment; filename=" + fileName + ".csv");
foreach (DataColumn column in table.Columns)
{
context.Response.Write(column.ColumnName + ";");
}
context.Response.Write(Environment.NewLine);
foreach (DataRow row in table.Rows)
{
for (int i = 0; i < row.ItemArray.Length; i++)
{
context.Response.Write(row[i].ToString().Replace(";", string.Empty) + ";");
}
context.Response.Write(Environment.NewLine);
}
context.Response.End();
}
I know the way I'm using fileName is wrong in this context, as fileName is actually storing file path + file name in my code. Any way to specify a file path?
The only other solution I can think of is if I created the some sort of file on the page and had them right click + save as. Is this a bad alternative? Are there others?
No. The web application doesn't know anything about the local file system. (Indeed, aside from the content-disposition header, the HTTP protocol doesn't even really know what a "file" is.)
What you're doing (aside from having the full path in the content-disposition header) is correct. The standard way to send a file to a web client is to set that header and write the file content to the output. What happens on the client-side is entirely up to the web browser. If the user's web browser is set to automatically save downloads to a specific folder without prompting then you can't change that from the server.
no, where the file is saved on the user's computer is dictated by the web browser, it has nothing to do with the web server. think about it, you don't know what operating system a site visitor is running, let alone some arbitrary path you specify on the server.

Problem with relative path in System.file.io of asp.net

I'm storing the file path in the database as ~/FolderName/FileName and when i try to open the file using System.IO.FileInfo(filePath) in this manner. It is not able to decipher the file path. Moreover i'm using this statement in a class DownloadFile, so i'm not able to use Page.Server.MapPath. Is there a work around for this problem.
These are the following lines of code that i'm using:
if (dr1.Read())
{
String filePath = dr1[0].ToString();
HttpContext.Current.Response.ContentType = "APPLICATION/OCTET-STREAM";
String disHeader = "Attachment; Filename=\"" + fileName + "\"";
HttpContext.Current.Response.AppendHeader("Content-Disposition", disHeader);
System.IO.FileInfo fileToDownload = new System.IO.FileInfo(filePath);
string fullName = fileToDownload.FullName;
HttpContext.Current.Response.Flush();
HttpContext.Current.Response.WriteFile(fileToDownload.FullName);
sqlCon.Close();
}
where the filepath is of the format ~/ComponentFolderForDownloading/FileName.exe
How can i solve this problem?
If you can't use Server.MapPath for determining the file location, you need to use something else. The FileInfo class can not take an ASP.NET virtual path in its constructor. It needs the real, physical path of the file.
You'll need to strip the ~/ from the front of the path; perhaps exchange the / for a \, and then use Path.Combine with the root directory of your application to find the physical location. But that assumes that your locations are in physical directories - not virtual ones.
Server.MapPath was, of course, made specifically to do this.
An alternative would be to store the real, physical locations of the files in the DB; either in addition to or in stead of the virtual, ASP.NET ones.
If you know you are running in IIS, you can use:
HttpContext.Current.Server.MapPath("~/someurl");

Categories