Opening file with different name shown to user - asp.net

I have a directory with a lot of files in it named: file001.pdf, file002.pdf etc.
Now I want a linkbutton in asp.net witch opens one of the above files with an other name!
So for example the linkbutton show's and opens when clicked the pdf: newname.pdf.
Is this possible in asp.net? I only want the client to see the newname.pdf and I want the file001.pdf remains on the server.

You could try reading in the file into a Byte array (or as a stream) and then output the file with a different name?
Byte[] myFile = System.IO.File.ReadAllBytes("~/MyPdf.pdf");
Response.ContentType = "application/pdf";
Response.AppendHeader("content-disposition", "filename=NEW_NAME.pdf");
Response.OutputStream.Write(myFile, 0, myFile.Length);
Response.Flush();
Note, not tested this. But it should point you in the right direction...

Related

ASP.NET - PDF downloading in .aspx format instead of PDF

I created a PDFViewer form in ASP.NET, and it works fine within the app. In the last part of the code, I use these lines to generate the PDF file from information I used previously (I'm using the PDFSharp library):
MemoryStream stream = new MemoryStream();
pdf.Save(stream, false);
response.Clear();
response.ContentType = "application/pdf";
response.AddHeader("content-length", stream.Length.ToString());
response.BinaryWrite(stream.ToArray());
response.Flush();
stream.Close();
response.End();
The file looks good, I see all the PDF browser options to print, zoom, downlad, etc.
The issue I'm having is, when I click on the download button, it wants to download the PDF as "PDFname.aspx", instead of "PDFname.pdf", although I am specifying the content type is "application/pdf". Which other thing could be missing?

PDF from content of asp.net page

I'm trying to create a pdf of the content on a page ("returnsPage.aspx?id="returnId) and allow the user to download this directly when clicking the button.
However in my onClick method I have the following code:
lnkLoadPDF.CommandArgument = "/returns/returnsPage.aspx?id="+returnId.ToString();
string virtualPath = lnkLoadPDF.CommandArgument;
string fileName = System.IO.Path.GetFileName(virtualPath);
Response.Clear();
Response.AddHeader("content-disposition", "attachment; filename=" + fileName);
Response.WriteFile(virtualPath);
Response.ContentType = "";
Response.End();
Response.Redirect("/returns/returnsPage.aspx?id="+returnId);
which returns this error:
'/returns/returnsPage.aspx?id=23' is not a valid virtual path.
Can anyone please tell me what I'm doing wrong?
Thanks!
In order to turn a webpage into a pdf, you must convert it to pdf on the server. In order to do that, you must have a program on the server that can do that for you.
I've tried a variety of webpage-to-pdf converters and one of the better ones is a free, open source program called wkhtmltopdf.
After you create the pdf, you can either redirect the user to the newly created pdf (discouraged), or prompt them to download it with a savefile dialog.
If you get stuck, just search for wkhtmltopdf on stackoverflow or post another question.
You can't send a file to the client and redirect him to a new location during the same request. You also can't create a PDF from a webpage without some kind of component that converts the HTML into a PDF, it's (quite a bit) more tricky that what I think you're trying to attempt.
As for your exception, are you sure returnsPage.aspx exists? :)

How to designate the name of a file that a user downloads via an ASHX downloader?

This is my first time writing code that allows a user to download a file uploaded by another user.
I've written an ASHX file, download.ashx, with code that looks like this:
s = context.Request.QueryString.ToString();
byte[] buffer = new ReplacementTicketFileIO().GetSpecifiedFile(s);
context.Response.BinaryWrite(buffer);
context.Response.Flush();
context.Response.End();
When a user clicks on a link to download.ashx with the appropriate querystring, the file is downloaded, but the browser wants to display the content in the browser window. If the user right-clicks on the link, he can download the file, but the name of the file defaults to download.ashx.
I would like to accomplish two things:
1) I would like to be able to specify the default name of the file downloaded on the user's device based on the querystring.
For instance, if the user clicks on download.ashx?linkedfile=car.pdf, I would like for the browser to default to car.pdf for the name of this file.
2) I would like for the browser to default to saving the link, as opposed to opening the link in the browser window.
Is it reasonable for me to want to do this, or is there a better way to download files? Please let me know.
Set the Content-Disposition HTTP header. E.g.
Content-Disposition: attachment; filename=hello.jpg
You can do that in C# using:
Response.AddHeader("Content-Disposition", "attachment; filename=hello.jpg");
Here is something I have for excel files and I believe it forces a download rather than a new window. There is a page property for QueryString. You would just need to capture the QueryString and use it in this code as well as determining the content type. The String.Format will give you clean code.
private string _ExcelFilename
{
get
{
return (Request.QueryString["xls"] != null) ? Request.QueryString"xls"] : "bis";
}
}
Page.Response.Clear();
Page.EnableViewState = false;
Page.Response.Clear();
Page.Response.ContentType = "application/vnd.ms-excel";
Page.Response.AppendHeader("Content-Disposition", String.Format("attachment; filename={0}_{1}.xls", _ExcelFilename, DateTime.Now.ToString("yyyyMMdd")));
Page.Response.Write(excel);
Page.Response.Flush();
Page.Response.End();

Response.WriteFile

There is one URL with specific syntax to download a file.
http://www.hddownloader.com/?url=http://www.youtube.com/watch?v=N-HbxNtY1g8&feature=featured&dldtype=128
The user enters the file name in the textbox and presses the download button.In the click event the Response.WriteFile is called which sends the file to the client.
Now I want to create another website with a page, in which the user enters the filename and presses the download button to download that file.
Now I want to utilise the first URL for that. I dont want to use Response.Redirect, because by that way, the user will come to know that I am using mydownload.com.
How can I acheieve that.
One way is : When we download something from microsoft's website, a small popup window(with no close, maximise and minimise button) and then the save dialog box appears.
How to achieve this or another to achieve the same ?
You could first download the file from the remote location on your server using WebClient.DownloadFile:
using (var client = new WebClient())
{
client.DownloadFile("http://remotedomain.com/somefile.pdf", "somefile.pdf");
Response.WriteFile("somefile.pdf");
}
or if you don't want to save the file temporary to the disk you could use the DownloadData method and then stream the buffer into the response.
UPDATE:
Example with the second method:
using (var client = new WebClient())
{
var buffer = client.DownloadData("http://remotedomain.com/somefile.pdf");
Response.ContentType = "application/pdf";
Response.AppendHeader("Content-Disposition", "attachment;filename=somefile.pdf");
Response.Clear();
Response.OutputStream.Write(buffer, 0, buffer.Length);
Response.Flush();
}

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