I have a "Download PDF" button that render a ReportViewer and open it in browser using Adobe Reader.
Here's the code:
Warning[] warn = null;
String[] streamids = null;
String mimeType = "application/pdf";
String encoding = String.Empty;
String extension = String.Empty;
Byte[] byteViewer;
byteViewer = report.LocalReport.Render("pdf", null, out mimeType, out encoding, out extension, out streamids, out warn);
Response.Buffer = true;
Response.Clear();
Response.ContentType = "application/pdf";
Response.AddHeader("content-disposition", "inline; filename=" + fileName + ".pdf");
Response.BinaryWrite(byteViewer);
Response.Flush();
Response.End();
But now, instead of opening the pdf, i want to open a download dialog to download the file. What changes in the code should I do?
#edit
The answers in that question are way too extensive, my question was asked to simplify the process of downloading a ReportViewer, and also adding a reference for future C# programmers that may encounter this question, without having to dig through lines of useless php code to find the answer.
To simplify the code for future StackOverflow users that may find this question:
in Response.AddHeader("content-disposition", "inline; filename=" + fileName + ".pdf");, just change inline to attachment, and that will download the file instead of opening in the browser.
This answer is too simple, so I will check "community wiki" to be fair.
Related
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);
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();
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.
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();
}
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();
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.
I try to download a zip file made by Ionic.Zip.dll from an asp.net c# web form application like this:
zip.AddEntry("filename", arraybyte);
Response.Clear();
Response.BufferOutput = false;
Response.ContentType = "application/zip";
Response.AddHeader("content-disposition", "filename=SuppliersDocuments.zip");
zip.Save(Response.OutputStream);
Response.Close();
But I get Failed - network error like this:
Error just occurs in chrome and it works properly in another browsers.
Error does not occur on my localhost and it happens only on the main server.
It would be very helpful if someone could explain solution for this problem.
I have the same issue and this happens in Chrome. This issue is happening on Chrome v53 and later which is explained here.
To overcome this issue I suggest you get the length of the file and use Content-Length in the header and pass the length of the file.
string fileName = string.Format("Download.zip");
Response.BufferOutput = false; // for large files
using (ZipFile zip = new ZipFile())
{
zip.AddFile(path, "Download");
Response.Clear();
Response.Buffer = true;
Response.ContentType = "application/zip";
Response.AddHeader(name: "Content-Disposition", value: "attachment;filename=" + fileName);
Int64 fileSizeInBytes = new FileInfo(path).Length;
Response.AddHeader("Content-Length", fileSizeInBytes.ToString());
zip.Save(Response.OutputStream);
Response.Flush();
}
Response.Close();
I am successfully able to export a report from a report viewer to a PDF file using this code:
private void ExportReport(string exportType)
{
if (ReportViewerControl.LocalReport.ReportPath == null)
{
LiteralReportErrorMessage.Text = "Please select a report to view before exporting.";
return;
}
Warning[] warnings;
string[] streamIds;
string mimeType = string.Empty;
string encoding = string.Empty;
string extension = string.Empty;
string filename = "RSLF";
byte[] bytes = ReportViewerControl.LocalReport.Render(exportType, null, out mimeType, out encoding, out extension, out streamIds, out warnings);
Response.Buffer = true;
Response.Clear();
Response.ContentType = mimeType;
Response.AddHeader("content-dispostion", "attachment; filename=" + filename + "." + extension);
Response.BinaryWrite(bytes);
Response.Flush();
}
The problem I am having is that this method is called from a button click event handler. The handler does nothing else but call this method then return.
The report exports just fine, but instead of the user being prompted with a "Save As..." dialog (as I really would prefer) the PDF opens in the browser in the same tab that the original page was on. When the user clicks the "Back" button, all of the report settings are lost and need to be re-entered.
I don't care if the report opens in the browser, but is it possible to force it to open in a new tab or window? Even better, is it possible for me to alter the method above to prompt the user to save the file rather than show it in the browser?
I actually found my problem...I misspelled "content-disposition". Changing it from "content-dispostion" to "content-disposition" worked.
How silly!
Just try to erase any buffered HTML output with the Clear method in your Response. This code should prompt a "Save As" dialog.
Response.Clear();
Response.ClearHeaders();
Response.ContentType = mimeType;
Response.AppendHeader("content-disposition", "attachment; filename=" + filename + "." + extension);
Response.BinaryWrite(bytes);
Response.Flush();
Response.SuppressContent = true;
HttpContext.Current.ApplicationInstance.CompleteRequest();
I try to load a small pdf file to client browser. I redirect to download_page.aspx that does the following:
Response.ClearHeaders();
Response.ContentType = "application/pdf";
Response.Clear();
Response.AppendHeader("Content-Disposition", "attachment");
Response.TransmitFile(file);
Response.Flush();
Problem:
When I redirect to download_page.aspx from a link or from a button.OnClientClick="javascript:window.open('download_page.aspx?index=20')"
it works. PDF opens in client browser.
However, when I click on a button that does something on the page and then i use ClientScript.RegisterStartupScript to redirect to download_page.aspx, then download_page.aspx just blinks (flashes) and closes, no pdf loaded.
This is IE7, IE8 problem. It works in Firefox.
Any help appreciated.
Thank you,
Raman.
First of all, you don't need to ClearHeaders Clear and Flush, so your code should look like:
Response.ContentType = "application/pdf";
Response.AppendHeader("Content-Disposition", "attachment");
Response.TransmitFile(file);
Now, you should also improve the Content-Disposition header value and add the file name to ease end-users browser experience. IE is different than other with regards with how the file name can be encoded in case it has special characters, so here is a sample code that you might use or change to your will:
public static void AddContentDispositionHeader(HttpResponse response, string disposition, string fileName)
{
if (response == null)
throw new ArgumentNullException("response");
StringBuilder sb = new StringBuilder(disposition + "; filename=\"");
string text;
if ((HttpContext.Current != null) && (string.Compare(HttpContext.Current.Request.Browser.Browser, "IE", StringComparison.OrdinalIgnoreCase) == 0))
{
text = HttpUtility.UrlPathEncode(fileName);
}
else
{
text = fileName;
}
sb.Append(text);
sb.Append("\"");
response.AddHeader("Content-Disposition", sb.ToString());
}
Now, your code can be written as:
Response.ContentType = "application/pdf";
AddContentDispositionHeader(Response, "attachment", filename);
Response.TransmitFile(file);
The last thing is: make sure nobody deletes the files or writes to it during its transmission.
I met the same condition as yours.
I finally solved it.
Don't use window.open. You can simply use
window.location = 'download_page.aspx?index=20'
Note that the original page will remain well.
Reference from here and from here
Currently I have the text file going to desktop, in ASP how can I prompt a file save dialog for the user? The result is string from the streamreader as "result" as follows:
StreamWriter FileWriter = new StreamWriter(Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.Desktop), "file.txt"));
FileWriter.Write(result);
FileWriter.Close();
String FileName = filename;
String FilePath = filepath;
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();
response.End();
Response.AppendHeader("Content-Disposition", "attachment");
StreamWriter FileWriter = new StreamWriter(Response.OutputStream);
FileWriter.Write(result);
I didn't try the code, but maybe you need to omit the call to FileWriter.Close() since it will try to dispose the stream. If not, then you should be using using instead. If it's too problematic, write to the stream directly with its Write method or use a MemoryStream.
An example from one of my apps that does it.
protected void Page_Load(object sender, EventArgs e)
{
string tempFileName = Request["tempFileName"]; // the temp file to stream
string attachFileName = Request["attachFileName"]; // the default name for the attached file
System.IO.FileInfo file = new System.IO.FileInfo(Path.GetTempPath() + tempFileName);
if (!file.Exists)
{
pFileNotFound.Visible = true;
lblFileName.Text = tempFileName;
}
else
{
// clear the current output content from the buffer
Response.Clear();
// add the header that specifies the default filename for the
// Download/SaveAs dialog
Response.AddHeader("Content-Disposition", "attachment; filename=" + attachFileName);
// add the header that specifies the file size, so that the browser
// can show the download progress
Response.AddHeader("Content-Length", file.Length.ToString());
// specify that the response is a stream that cannot be read by the
// client and must be downloaded
Response.ContentType = "application/octet-stream";
// send the file stream to the client
Response.WriteFile(file.FullName);
}
}
string path = Server.MapPath(your application path);
WebClient client = new WebClient();
byte[] data = client.DownloadData(new Uri(path));
Response.Clear();
Response.ContentType = "application/pdf";
Response.AppendHeader("Content-Disposition", String.Format("attachment; filename={0}", "aspnet.pdf"));
Response.OutputStream.Write(data, 0, data.Length);
try this code.. its helpful
Don't know if its still open but just to help others
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();
}
If I understand you correctly, you first had a 1-tier (desktop) app that was saving a file using C# to the user's file system. You are now trying to transition to a 2-tier app with your C# code running on the server tier, and the user's browser representing the other tier. There is nothing you can do in C# on the server to write a file to the browser user's file system directly.
That being said, what you need to do is write the file to the HTTP response stream with a content type of something like application/octet-stream. Are you actually using ASP or ASP.NET? If the latter, you should have access to the response stream through a variety of means, but start with the Response object (available from the page, but also available via HttpContext.Current.Response).