23

I want to make the browser download a PDF document from server instead of opening the file in browser itself. I am using C#.

Below is my sample code which I used. It not working..

string filename = "Sample server url";
response.redirect(filename);
Wayne Werner
  • 49,299
  • 29
  • 200
  • 290
Arun
  • 1,644
  • 9
  • 25
  • 41

5 Answers5

39

You should look at the "Content-Disposition" header; for example setting "Content-Disposition" to "attachment; filename=foo.pdf" will prompt the user (typically) with a "Save as: foo.pdf" dialog, rather than opening it. This, however, needs to come from the request that is doing the download, so you can't do this during a redirect. However, ASP.NET offers Response.TransmitFile for this purpose. For example (assuming you aren't using MVC, which has other preferred options):

Response.Clear();
Response.ContentType = "application/pdf";
Response.AppendHeader("Content-Disposition", "attachment; filename=foo.pdf");
Response.TransmitFile(filePath);
Response.End(); 
Marc Gravell
  • 1,026,079
  • 266
  • 2,566
  • 2,900
  • thanks for reply... if i give a url instead of foo.pdf in ur answer will it work...? – Arun Dec 21 '11 at 13:32
  • @Neon no; you actually need to transmit the contents if doing this; `TransmitFile` takes a *local* file path, IIRC. – Marc Gravell Dec 21 '11 at 13:33
  • @Neon to clarify - if the URL is somewhere else, you could act as a *proxy* to that URL; but you cannot say "go and get the file from [over there], and treat it as a download" - the server that provides the final content gets to choose the content type and disposition. – Marc Gravell Dec 21 '11 at 13:35
  • then what i must do to download the file from a url.. is there is anyother method instead of using TransmitFile – Arun Dec 21 '11 at 13:40
  • @Neon yes - but it depends on the size; if the expected size is small, just use `WebClient` to get the bytes (`client.DownloadData(url)`), then use `Response.BinaryWrite(blob)` to send it onwards. If the expected size if large, you'd need to do that in a loop using a `HttpWebResponse` - more complex. – Marc Gravell Dec 21 '11 at 13:47
  • Actually file size may vary. both small sized file and big sized file. – Arun Dec 21 '11 at 13:53
  • @Neon then assume the worst and setup a read/write proxy loop from a remote request, throwing the data over in small chunks (using, say, a 10k buffer). – Marc Gravell Dec 21 '11 at 14:06
  • 1
    What would be the preferred options using MVC? Thanks –  Nov 16 '15 at 14:32
  • 3
    @WashingtonGuedes `return File(filePath, "application/pdf", "foo.pdf");` – Marc Gravell Nov 16 '15 at 14:52
  • @MarcGravell please can you updated your answer to include the preferred options for the MVC – Hakan Fıstık Dec 25 '15 at 17:35
  • @MarcGravell: while downloading it locally i am getting `access denied error` even after unchecking the read only part and allowing access to all users. why ? – Nad Jul 27 '17 at 07:29
  • I get "Thread has been aborted" error, but it still attempts to open an Outllook MSG file, but it's called it "H_Visual" without an extension. What's going on? – Fandango68 Apr 18 '19 at 01:49
4

If you want to render the file(s) so that you could save them at your end instead of opening in the browser, you may try the following code snippet:

//create new MemoryStream object and add PDF file’s content to outStream.
MemoryStream outStream = new MemoryStream();

//specify the duration of time before a page cached on a browser expires
Response.Expires = 0;

//specify the property to buffer the output page
Response.Buffer = true;

//erase any buffered HTML output
Response.ClearContent();

//add a new HTML header and value to the Response sent to the client
Response.AddHeader(“content-disposition”, “inline; filename=” + “output.pdf”);

//specify the HTTP content type for Response as Pdf
Response.ContentType = “application/pdf”;

//write specified information of current HTTP output to Byte array
Response.BinaryWrite(outStream.ToArray());

//close the output stream
outStream.Close();

//end the processing of the current page to ensure that no other HTML content is sent
Response.End();

However, if you want to download the file using a client application then you'll have to use the WebClient class.

Shahzad Latif
  • 1,408
  • 12
  • 29
  • i am getting "Argument Out Of Range Exception" while executing in the line Response.BinaryWrite(outStream.ToArray()); – Arun Dec 21 '11 at 13:49
  • Have you filled the contents in the outStream? Read your file into the memory stream and I hope it'll be working fine. – Shahzad Latif Dec 21 '11 at 13:51
  • Please try this snippet to convert file to MemoryStream: using (FileStream fileStream = File.OpenRead(filePath)) { MemoryStream outStream = new MemoryStream(); outStream.SetLength(fileStream.Length); fileStream.Read(outStream.GetBuffer(), 0, (int)fileStream.Length); } – Shahzad Latif Dec 21 '11 at 14:34
  • Your "WebClient class" is off!! – Diogo Cid Nov 13 '15 at 15:39
3

I use this by setting inline parameter to true it will show in browser false it will show save as dialog in browser.

public void ExportReport(XtraReport report, string fileName, string fileType, bool inline)
{
    MemoryStream stream = new MemoryStream();

    Response.Clear();

    if (fileType == "xls")
        report.ExportToXls(stream);
    if (fileType == "pdf")
        report.ExportToPdf(stream);
    if (fileType == "rtf")
        report.ExportToRtf(stream);
    if (fileType == "csv")
        report.ExportToCsv(stream);

    Response.ContentType = "application/" + fileType;
    Response.AddHeader("Accept-Header", stream.Length.ToString());
    Response.AddHeader("Content-Disposition", String.Format("{0}; filename={1}.{2}", (inline ? "Inline" : "Attachment"), fileName, fileType));
    Response.AddHeader("Content-Length", stream.Length.ToString());
    //Response.ContentEncoding = System.Text.Encoding.Default;
    Response.BinaryWrite(stream.ToArray());

    Response.End();
}
0

In case if we are trying to write a bytes array then we can use below one.

            Response.Clear();
            Response.ContentType = "application/pdf";
            Response.AppendHeader("Content-Disposition", "attachment; filename=file.pdf");
            Response.BufferOutput = true;
            Response.AddHeader("Content-Length", docBytes.Length.ToString());
            Response.BinaryWrite(docBytes);
            Response.End();
Varinder
  • 1,780
  • 2
  • 11
  • 18
-2

They are almost same in most of the cases but there is a difference:

Add Header will replace the previous entry with the same key

Append header will not replace the key, rather will add another one.