When the user clicks a button, I want to build a string, then have the user download that string as a file (it's a CSV file).
var response = HttpContext.Current.Response;
response.ClearContent();
response.Clear();
byte[] bytes = Encoding.ASCII.GetBytes(csvtext);
using (var stream = new MemoryStream(bytes))
{
response.AddHeader("Content-Disposition", "attachment; filename=somefile.csv");
response.AddHeader("Content-Length", stream.Length.ToString());
response.ContentType = "text/plain";
stream.WriteTo(response.OutputStream);
}
This is what I have so far, and I have a feeling I'm pretty close, but I get the following error message:
Microsoft JScript runtime error: Sys.WebForms.PageRequestManagerParserErrorException: The message received from the server could not be parsed. Common causes for this error are when the response is modified by calls to Response.Write(), response filters, HttpModules, or server trace is enabled.
Details: Error parsing near '[The first bit of the CSV file]'.
I'm at a loss, and a deadline is fast approaching. Any help is greatly appreciated.
My guess is that you are in an AJAX Update Panel. If you are doing this type of action it must be done via a postback.
You can't do this with a partial/async postback with Ajax. You'll need to make whatever button you have triggering this download a PostBackTrigger for your UpdatePanel. Details here: http://www.asp.net/Ajax/Documentation/Live/mref/T_System_Web_UI_PostBackTrigger.aspx
Related
I inherited an .net application that allows users to download a pdf. Now, I am able to download the pdf file when I run locally but when I deploy to IIS server I run into problems. The download works on Firefox but doesnt work on Chrome, and sometimes on IE. The fact that I can download it on my local development environment tells that it could be something with IIS configuration or maybe my code. The pdf is stored in ms sql server 2012 table as varbinary. I provided some code below that is used to read the data. Please let me know if there are other information you all need. Also, I checked the iis logs and I am getting 200 status codes for everything. Nothing stands out in there.
if(Session["DetailID"] != null)
{
//get the file
DataTable dt = sp_Attachment_Download(lblAttachmentIDD.Text);
DataRow row = dt.Rows[0];
string name = (string)row["AFileName"];
string contentType = (string)row["AFileType"];
Byte[] data = (Byte[])row["AFile"];
/// Send the file to the browser
Response.AddHeader("Content-type", contentType);
Response.AddHeader("Content-Disposition", "attachment; filename=" + name);
Response.BinaryWrite(data);
Response.Flush();
Response.Close();
}
EDITED----------
I am using the developer tools for IE and Chrome and found something interesting. Chrome gives me the following error when I click on the link:
interpreted as Document but transferred with MIME type application/pdf:
IE doesnt give an error but something caught my attention. I my REQUEST header, ACCEPT does not contain application/pdf and the RESPONSE Content-Type has application/pdf. Could this be something? How can I set the ACCEPT to include application/pdf in aspx page?
I had kinda similar issue when downloading pdf from chrome as in my case filename had a comma in it and that chrome apparently didn't like it, so I removed comma from filename and it worked.
PS: Please try not to use Response.Close(). It aborts the thread and throws exception.
Response.Clear();
Response.ContentType = "application/pdf";
Response.AddHeader("content-disposition", "attachment; filename=" + fileName.Replace(",",,");
Response.CacheControl = "No-cache";
Response.Write(data);
Response.Flush();
Response.SuppressContent = true;
HttpContext.Current.ApplicationInstance.CompleteRequest();
Maybe this will help, here's my code to do the same thing. One thing that I noticed is that you're not specifying the file length, which I believe is required. Please note that pFileData is class that contains FileName, a string, and FileData, a byte[].
System.Web.HttpResponse Response = System.Web.HttpContext.Current.Response;
Response.Clear();
Response.ClearHeaders();
Response.ContentType = "application/pdf";
Response.AddHeader("Content-Disposition", "attachment;filename=" + pFileData.FileName);
Response.AddHeader("Content-Length", pFileData.FileData.Length.ToString());
Response.BufferOutput = false;
Response.BinaryWrite(pFileData.FileData);
Response.Flush();
Response.SuppressContent = true;
HttpContext.Current.ApplicationInstance.CompleteRequest();
Response.End();
I have a code set that runs on the server, which correctly generates a zip file and stores it on the server. I have that file location as a physical path.
Nothing I have attempted has allowed me to use the response to the client to download that file.
Attempt 1:
System.IO.FileInfo fi = new System.IO.FileInfo(zipFilePath);
//setup HTML Download of provided Zip.
//application/zip
Response.ClearContent();
Response.Clear();
Response.ClearHeaders();
Response.Buffer = true;
Response.ContentType = "application / zip";
Response.AddHeader("Content-Disposition",
"attachment; filename=\"" + System.IO.Path.GetFileName(zipFilePath) + "\";");
Response.AddHeader("Content-Length", fi.Length.ToString());
Response.TransmitFile(zipFilePath);
Response.Flush();
Response.End();
No result. Code executes without error but there is no download to the client.
Attempt 2:
//Almost the same as attempt 1, but with WriteFile instead
Response.WriteFile(zipFilePath);
No Result, same as Attempt 1.
Attempt 3:
//Note: Same Header Section as Attempts 1 and 2
System.IO.BinaryReader reader = new System.IO.BinaryReader(new System.IO.FileStream(zipFilePath, System.IO.FileMode.Open));
int CHUNK = 1024;
List<byte> FileArray = new List<byte>();
while (reader.BaseStream.Position < reader.BaseStream.Length)
FileArray.AddRange(reader.ReadBytes(CHUNK));
byte[] bArray = FileArray.ToArray();
reader.Close();
Response.OutputStream.Write(bArray, 0, bArray.Length);
Response.Flush();
Response.End();
No Result, Same as previous attempts
Attempt 4:
//Identical to Attempt 3, but using BinaryWrite
Response.BinaryWrite(bArray);
No Result, Same as previous Attempts.
The Question
Every one of these code blocks runs with no error, But The Save File dialog NEVER appears. I get nothing at all. I cannot figure out for the life of me what I might be missing.
The File Path has been verified as correct
The Code is running on the server, not on the client, I cannot use the 'WebClient.Download' method for this reason
If anyone has any suggestions, I'm all ears. I have no idea how to get this file to download to the client.
I tested your code (attempt 1) and got it working fine with a test file. If the file path would be wrong, you'd get an System.IO.FileNotFoundException so that's probably not the issue.
A couple of ways to address this:
Try inspecting the webpage in, for example, Chrome by right-clicking
and choose inspect. Then click on Network tab, and refresh the
page (where you're supposed to get the file). Check the response
headers for that request - what is it?
Try setting content-type to application/octet-stream
Use debugger in Visual Studio and step through.
This turned out to be an Ajax related error causing issues between UpdatePanels and POST Responses.
The issue was fixed on the page load of the page by adding the call
ScriptManager.GetCurrent(Page).RegisterPostBackControl(btnGenerate);
I am writing large CSV files to the Response with Response.BufferOutput set to false. This is because the file has the potential to take a long time to download so the user can see some progress. I generate a line for the CSV from a object and write to the response using Response.Write().
This works well however if there is an unexpected error after the Response has started writing then the client will receive a file with only part of the data and could be missing lots of lines but they might not realise it.
Is there a way to somehow cancel the file download without buffering all the content? Could there be some way to indicate that the response is invalid so the browser disregards the file?
Code below shows the main idea of my code
public void StreamCsvFile(string fileName,List<myObject> myObjectList)
{
Response.Clear();
Response.ContentType = "text/csv";
Response.AddHeader("content-disposition", "filename=" + fileName);
Response.BufferOutput = false;
string headerLine = GetHeaderLine();
Response.Write(headerLine)
try
{
foreach(var myObject in myObjectList)
{
string line = myObject.ToCsvString();
Response.Write("\n" + line);
}
}
finally
{
Response.End();
}
}
Write to a temporary file first.
Set the content-length on the response.
Use Response.TransmitFile to send this temp file.
Browsers will reject download if content length doesn't match.
I'm trying to create a file handler for users to download files when their filenames are clicked on a web page. I've implemented this a few times without issues, but I'm currently getting an error which I can't get my head around.
Code:
protected void btnViewFile_Click(object sender, EventArgs e)
{
var btnViewFile = sender as LinkButton;
Response.Clear();
Response.ContentType = "application/octet-stream";
Response.AppendHeader("Content-Disposition", "attachment; filename=" + btnViewFile.CommandArgument.ToString());
Response.WriteFile(Server.MapPath(btnViewFile.CommandArgument));
Response.End();
}
If I look at the browser console, I can see:
Uncaught Sys.WebForms.PageRequestManagerParserErrorException: Sys.WebForms.PageRequestManagerParserErrorException: The message received from the server could not be parsed.
No exceptions appear to be thrown in the code, the requested file is converted into the correct full path; and I've tried quite a few different things - clearing headers manually, flushing before ending, giving a more explicit content-type header, using AddHeader instead of AppendHeader, using TransmitFile rather than WriteFile, and quite a bit more.
Any ideas?
In case anyone else comes across this situation, the problem was that I was registering it as a postback control in ScriptManager, not an async postback control.
D'oh!
Im using ssrs through a reports server to generate a resultStream byte array using ReportExecutionService.Render() which I am currently serving to the user with the following code. Is there a way I can use this same byte array to automatically open the report in a new browser window instead of going to the save/open dialog?
public void RenderReport (byte[] reportDigits, ReportItem reportItem)
{
HttpResponse response = HttpContext.Current.Response;
response.Clear();
response.ContentType = reportItem.ReportMimeType;
response.AddHeader("Content-Disposition", string.Format("attachment; filename={0}", reportItem.ExportName));
response.OutputStream.Write(reportDigits, 0, reportDigits.Length);
response.End();
}
In the past I have used a separate ReportViewer.aspx page that I would open first then display the report but would like to do it all in code behind if that is possible.
Thanks
It's this line:
response.AddHeader("Content-Disposition", string.Format("attachment; filename={0}", reportItem.ExportName));
Thats causing it to be downloaded. Comment out that line, and as long as the browser can handle the mime type, it will render in the browser window.
Simply change the Header that you are adding to something other than an attachement. Make it the format of your data--and hopefully the browser will recognize it.