asp.net ashx handler prompting download instead of displaying file - asp.net

I implemented a generic handler in my application which works great for images, but when I manually type the handler URL in the browser with the image's querystring it prompts download instead of displaying. Here is my code:
public void ProcessRequest(HttpContext context)
{
if (this.FileName != null)
{
string path = Path.Combine(ConfigurationManager.UploadsDirectory, this.FileName);
if (File.Exists(path) == true)
{
FileStream file = new FileStream(path, FileMode.Open);
byte[] buffer = new byte[(int)file.Length];
file.Read(buffer, 0, (int)file.Length);
file.Close();
context.Response.ContentType = "application/octet-stream";
context.Response.AddHeader("content-disposition", "attachment; filename=\"" + this.FileName + "\"");
context.Response.BinaryWrite(buffer);
context.Response.End();
}
}
}
I am using the octet-stream because I'm dealing with more than just images and I don't always know the content type of the file. Thanks in advance!

The only way is to specify correct ContentType so the browser know what to do with receiving file, depending on installed plugins (for example, view pdf files in browser frame) and system assosiations (for example, offer to open document in MS Office instead of simple download)
You can try to specify Content Type depending on file extension, i.e.:
if(Path.GetExtension(path) == ".jpg")
context.Response.ContentType = "image/jpeg";
else
context.Response.ContentType = "application/octet-stream";

If you store the ContentType as part of the files metadata, when you pull it back down your could use it.
theFile = GetFile(id)
context.Response.ContentType = theFile.Type;

The content-disposition header is the one that causes your browser to show the download dialog. Remove that line and it will show in the browser.

Related

Pdf file damaged on download in Chrome and Firefox

I am using iTextSharp for creating pdf reports (files) and storing those on the web server where my application resides. I am able to create the file, go into the storage folder and open the file without a problem. Notice: The user is not to get the file automatically
downloaded on creation.
I want to give the user the option to download "old" reports from the server with a button.
This is working fine in IE (10) but not in Chrome and Firefox. I always get the error message:
There was an error opening this document. The file is damaged and could not be repaired.
I have this image button and on click I send the user to a Generic Handler (since my page contains Update Panels) according to this post (only using it partially for now).
This is the code that actually downloads the file:
public void ProcessRequest(HttpContext context)
{
var _fileName = context.Request.QueryString["fileName"];
using (var _output = new MemoryStream())
{
//var _fileSeverPath = context.Server.MapPath(_fileName);
context.Response.Clear();
context.Response.ContentType = "application/pdf";// "application/pdf";
//context.Response.AppendHeader("Content-Length", _fileName.Length.ToString());
context.Response.AppendHeader("Content-Disposition", string.Format("attachment; filename=" + Path.GetFileName(_fileName)));
context.Response.WriteFile(_fileName);
context.Response.Flush();
context.Response.Close();
context.Response.End();
}
}
As I said, this works fine in IE but not in Chrome and Firefox.
When I open the file in Notepad it seams that I only get about 1/3 of the file when downloaded in Chrome and Firefox.
Any suggestions would be greatly appreciated. Been trying to resolve this for a few days now..
From HttpResponse.WriteFile Method (String)
When this method is used with large files, calling the method might
throw an exception. The size of the file that can be used with this
method depends on the hardware configuration of the Web server. For
more information, see article 812406, "PRB: Response.WriteFile Cannot
Download a Large File" on the Microsoft Knowledge Base Web site.
Try this instead:
public void ProcessRequest(HttpContext context)
{
var _fileName = context.Request.QueryString["fileName"];
context.Response.Clear();
context.Response.Buffer = true;
context.Response.ContentType = "application/pdf";
context.Response.AppendHeader(
"Content-Disposition",
string.Format("attachment; filename=" + Path.GetFileName(_fileName)));
using (var fs = new FileStream(_fileName, FileMode.Open, FileAccess.Read))
{
using (var sr = new StreamReader(fs, true))
{
int length = (int)fs.Length;
byte[] buffer;
using (BinaryReader br = new BinaryReader(fs, sr.CurrentEncoding))
{
buffer = br.ReadBytes(length);
context.Response.BinaryWrite(buffer);
}
}
}
context.Response.Flush();
context.Response.Close();
context.Response.End();
}
Ok, FINALLY.. I found the solution and it makes me feel like a fool at the same time..
Removed context.Response.Close(); ...then everything worked perfectly :)

Present a PDF Document on a Specific Page in ASP.NET

I am opening PDF documents using the following ASP.NET code,
Response.BufferOutput = true;
Response.Clear();
Response.ContentType = "application/pdf";
HttpWebRequest request = (HttpWebRequest)WebRequest.Create(documentURL);
using (HttpWebResponse responseDDRINT = (HttpWebResponse)request.GetResponse())
{
using (Stream stream = responseDDRINT.GetResponseStream())
{
int bufferSize = 1024;
byte[] buffer = new byte[bufferSize];
int bytesRead;
while ((bytesRead = stream.Read(buffer, 0, bufferSize)) > 0)
{
Response.OutputStream.Write(buffer, 0, bytesRead);
}
Response.Flush();
}
}
My question is does anyone know how to present the PDF starting at a specifice page. For example, if the PDF document is 15 pages, we would like it to open with page 10 initially showing instead of opening at page 1.
I experimented with the "#page=" open parameter by adding this header, but it did nothing.
Response.AddHeader("content-disposition", "inline; filename=test.pdf#page=3");
You'll have to manipulate the PDF file on the fly.
Use something like http://pdfsharp.com/PDFsharp/ to stream out a copy of the file starting at a certain page.
Current versions of Adobe ready no longer support the page syntax, but they do support the bookmark syntax.
Why don't you make your document reachable through a regular link or through an HTTPHandler?
you may use a PDF manipulation library like ItextSharp to get your work done.

What am I doing wrong with HttpResponse content and headers when downloading a file?

I want to download a PDF file from a SQL Server database which is stored in a binary column. There is a LinkButton on an aspx page. The event handler of this button looks like this:
protected void LinkButtonDownload(object sender, EventArgs e)
{
...
byte[] aByteArray;
// Read binary data from database into this ByteArray
// aByteArray has the size: 55406 byte
Response.ClearHeaders();
Response.ClearContent();
Response.BufferOutput = true;
Response.AddHeader("Content-Disposition", "attachment; filename=" + "12345.pdf");
Response.ContentType = "application/pdf";
using (BinaryWriter aWriter = new BinaryWriter(Response.OutputStream))
{
aWriter.Write(aByteArray, 0, aByteArray.Length);
}
}
A "File Open/Save dialog" is offered in my browser. When I store this file "12345.pdf" to disk, the file has a size of 71523 Byte. The additional 16kB at the end of the PDF file are the HTML code of my page (as I can see when I view the file in an editor). I am confused because I was believing that ClearContent and ClearHeaders would ensure that the page content is not sent together with the file content.
What am I doing wrong here?
Thanks for help!
I think you want a Response.End at the end of this method.
In a quick glance, you're missing Response.End();

ASP.NET stream content from memory and not from file

The users have requested the option to "download" a csv file representation of GridView contents. Does anyone know how to do this without saving the file to the server but rather just streaming it to the user from memory?
Thanks
Implement an IHttpHandler.
I used something similar to the following in the ProcessResponse for outputing a CSV that had previously been constructed in a database table...
public void ProcessRequest(HttpContext context)
{
HttpResponse response = context.Response;
HttpRequest request = context.Request;
//Get data to output here...
//Turn off Caching and enforce a content type that will prompt to download/save.
response.AddHeader("Connection", "close");
response.AddHeader("Cache-Control", "private");
response.ContentType = "application/octect-stream";
//Give the browser a hint at the name of the file.
response.AddHeader("content-disposition", string.Format("attachment; filename={0}", _filename));
//Output the CSV here...
foreach(BatchDTO.BatchRecordsRow row in dtoBatch.BatchRecords)
response.Output.WriteLine(row.Data);
response.Flush();
response.Close();
}
There are a number of libraries that make generating a CSV easier, you should just be able to pass it the Response.OutputStream to have it write to there rather than to a file stream.
Use context.Response.OutputStream.
Here's an example.
I created a StringBuilder and dump the contents to the Response object using the following code ("csv" is the StringBuilder variable).
Response.ContentType = #"application/x-msdownload";
Response.AppendHeader("content-disposition", "attachment; filename=" + FILE_NAME);
Response.Write(csv.ToString());
Response.Flush();
Response.End();
I have used the RKLib export library a few times to great effect, this uses a memory stream and can be given any datatable which it will export as a csv download:
http://www.codeproject.com/KB/aspnet/ExportClassLibrary.aspx

Zipping Files and Downloading them Using SaveAs Dialog

I have the following code to zip all the files and then save it to the harddisk. I want zip all the files (this is done) and then attach the zip file to the Response stream so that the user have the option to save it!
protected void DownloadSelectedFiles_Click(object sender, EventArgs e)
{
string path = String.Empty;
string zipFilePath = #"C:\MyZipFile.zip";
ZipOutputStream zipStream = new ZipOutputStream(File.Create(zipFilePath));
byte[] buffer = new byte[4096];
foreach (GridViewRow row in gvFiles.Rows)
{
bool isSelected = (row.FindControl("chkSelect") as CheckBox).Checked;
if (isSelected)
{
path = (row.FindControl("lblUrl") as Label).Text;
ZipEntry entry = new ZipEntry(Path.GetFileName(path));
entry.DateTime = DateTime.Now;
zipStream.PutNextEntry(entry);
using (FileStream fs = File.OpenRead(path))
{
int sourceBytes;
do
{
sourceBytes = fs.Read(buffer, 0, buffer.Length);
zipStream.Write(buffer, 0, sourceBytes);
} while (sourceBytes > 0);
}
}
}
zipStream.Finish();
zipStream.Close();
Response.ContentType = "application/x-zip-compressed";
Response.AppendHeader("Content-Disposition", "attachment; filename=SS.zip");
Response.WriteFile(zipFilePath);
Response.End();
}
I blogged about sending files like this a while ago. You might find something usefull in there.
http://absolutecobblers.blogspot.com/2008/02/downloading-and-deleting-temporary.html
If you are using IE, check that its not the old "cache is full"-bug that is showing its ugly face.
And if you have IE set to refresh cashe Automatically or on IE-start and have downloaded that zip-file broken the first time, then it could be that it uses the cached version of that zip-file after you fixed your routine and got a good zip.
Try to add:
Response.Buffer = true;
Response.Clear();
Response.ClearContent();
Response.ClearHeaders();
before your Response.ContentType
and add this:
Response.Flush()
Response.Close()
before response.end, and see if that changes anything.
So the result is this:
Response.Buffer = true;
Response.Clear();
Response.ClearContent();
Response.ClearHeaders();
Response.ContentType = "application/x-zip-compressed";
Response.AppendHeader("Content-Disposition", "attachment; filename=SS.zip");
Response.WriteFile(zipFilePath);
Response.Flush()
Response.Close()
Response.End();
Just some tips just from the top of the mind.
I also tried to save the zip file to the server folder and then giving a link to the user to download it but it says the same "The file is corrupted". This is very strange since I can open the same folder if I visit my server folder and manually open it!
Here is another thing I found. If I save the zip file in the Server's folder and then reference it using the url: http://localhost/MyApplication/ServerFolder/MyZipFile.zip.
If I go to the url and download the zip file I get the same error "File is corrupted". But if I manually go to the folder using file explorer and open the file then it works as expected.
Why and How?
And a long shot, try set the mime type to application/unknown, in this post there seems to be part of the solution to the posters problem:
http://jamesewelch.com/2008/12/03/sharpziplib-and-windows-extraction-wizard-errors/

Resources