Response.WriteFile writing the content twice - c#

Here is my code..
string attachment = "attachment; filename=Call-Details-Report-" + startDate.SelectedDate.Value.ToString("MM-dd-yyyy") + ".csv";
Response.Clear();
Response.ClearHeaders();
Response.ClearContent();
Response.AddHeader("Content-Disposition", attachment);
Response.ContentType = "text/csv";
Response.AddHeader("Pragma", "public");
Response.WriteFile(downloadLocation+"\\"+fileName);
Response.End();
I'm using the above code to download a csv file from a location.But surprisingly the contents gets written twice or some times thrice into the file that i download though actually it isn't so with the file on server.I'm writing my code in c#.
The above piece of code works perfectly in local machine,but the issue is in Production server.
Here is my complete Method
private void DownloadReport(string query)
{
string downloadFolderPath = "";
string filePath = "";
string dbAndApplicationServerStatus = ConfigurationManager.AppSettings["SameDBAndApplicationServer"] != null ? ConfigurationManager.AppSettings["SameDBAndApplicationServer"] : "1";
if (dbAndApplicationServerStatus == "0")
{
Log.Write("So the DB And Application are on differrent servers,hence trying to read Download folder path on DB Server....");
downloadFolderPath = ConfigurationManager.AppSettings["ReportDownloadLocation"] != null ? ConfigurationManager.AppSettings["ReportDownloadLocation"] : "-1";
Log.Write("Download Path is " + downloadFolderPath);
}
else
{
Log.Write("So the DB and Application and Db are on same server......");
downloadFolderPath = Server.MapPath("Download");
downloadFolderPath = downloadFolderPath.Replace("\\", "//");
if (!Directory.Exists(downloadFolderPath))
{
Directory.CreateDirectory(downloadFolderPath);
}
Log.Write("Download Path is " + downloadFolderPath);
}
string status="";
StringBuilder headerQuery = new StringBuilder();
StringBuilder rowQuery = new StringBuilder();
StringBuilder sqlQuery = new StringBuilder();
filePath = downloadFolderPath;
string folderName = DateTime.Now.ToString("MM-dd-yyyy");
string timeStamp = DateTime.Now.ToString("MM-dd-yy-HH-mm-ss");
string fileName = "Call-Details-Report-" + startDate.SelectedDate.Value.ToString("MM-dd-yyyy") + "_" + timeStamp + ".csv";
filePath = filePath + "/" + fileName;
bool commaRequired = false;
sqlQuery.Append("SELECT * INTO OUTFILE '");
sqlQuery.Append(filePath);
sqlQuery.Append("' FIELDS TERMINATED BY ',' OPTIONALLY ENCLOSED BY '\"' LINES TERMINATED BY '\n' FROM (");
headerQuery.Append("Select ");
rowQuery.Append("(Select ");
#region Creating Query
/*Sql Query is Created in this region*/
#endregion
if (!CdrSearch.WriteReportToFile(sqlQuery.ToString(),out status))
{
Log.Write("Failed to generate the file to download......");
WebPagesHelper.ShowMessage(ref lblMessage, WebPagesHelper.MessageType.Message, status);
}
else
{
Log.Write("Succesfully generated file to Download");
string downloadLocation = Server.MapPath("Download");
if (dbAndApplicationServerStatus == "0")
{
WebClient webClient = new WebClient();
string path = ConfigurationManager.AppSettings["DownloadURL"] != null ? ConfigurationManager.AppSettings["DownloadURL"].ToString() : "";
if (!Directory.Exists(downloadLocation))
{
Directory.CreateDirectory(downloadLocation);
}
if (File.Exists(downloadLocation + "\\" + fileName))
{
File.Delete(downloadLocation + "\\" + fileName);
}
webClient.DownloadFile(path + fileName, downloadLocation + "\\" + fileName);
}
Log.Write("Configured Download Location on Application" + downloadLocation);
string attachment = "attachment; filename=Call-Details-Report-" + startDate.SelectedDate.Value.ToString("MM-dd-yyyy") + ".csv";
Response.Clear();
Response.ClearHeaders();
Response.ClearContent();
Response.AddHeader("Content-Disposition", attachment);
Response.ContentType = "text/csv";
Response.AddHeader("Pragma", "public");
Log.Write(downloadLocation + "\\" + fileName);
Response.WriteFile(downloadLocation+"\\"+fileName);
Response.SetCookie(new HttpCookie("DStatus", "Completed"));
Response.End();
}
}
And the above method is called only once straight away on click of a button,so no question of any looping here.

You may check what the following lines are meant for :
webClient.DownloadFile(path + fileName, downloadLocation + "\\" + fileName);
Response.WriteFile(downloadLocation+"\\"+fileName);
Give a try by commenting out one of them, if they are really doing the same.
As a safe measure, please disable the button until your download is finished.
When i tried the following code (even published on IIS), it is just downloading once, as expected.
protected void Button1_Click(object sender, EventArgs e)
{
string attachment = "attachment; filename=Call-Details-Report-" + DateTime.Now.ToString("MM-dd-yyyy") + ".txt";
Response.ContentType = "text/html";
Response.AddHeader("Content-Disposition", attachment);
Response.AddHeader("Pragma", "public");
Response.WriteFile(#"C:\test.txt");
Response.SetCookie(new HttpCookie("DStatus", "Completed"));
Response.End();
}

There's obviously something hinky going on. You've said that it works in dev but not Prod - Are you using the same server config in both environemts (ie are you using 1 server in dev but 2 in prod?)
You've potentially got 3 steps, assuming I've understood your code...
Generate Report from SQL and write it to a file
If the file is stored on a different server, download it to the web server
Serve it
So, in the more complex scenario (which I assume Production is), At what step in the process do you start to see double entries? On the server the report is generated on, on the web servers' copy or only in the client after getting it from the Webserver?
I can't see any reason why your code to serve the file to the client would be duplicating data so can only assume it's happening before there at some point.
It would be helpful if you could use Firebug/Fiddler/??? to post the exact contents of the transmission from the webserver to the client
(Incidentally, you may want to look at the System.IO.Path class for manipulating paths, it makes your code more readable and robust - No more worrying about trailing slashes!)

ok so the real culprit was Response.WriteFile in this case.In my case i guess since the size of data was quite huge Response.WriteFile was not working as expected.I found some where that in case of large file downloads, its best to use Response.TransmitFile.Left with no other option i changed my code and used Response.TransmitFile and eureka! the problem was solved.No more duplicate records in downloaded file.Though the reason is still unknown, Response.TransmitFile solved the issue.....

Related

Error code 0x800704CD when generating PDF to zip

I know this question was asked & answered before, but the solutions don't work for me. I have to dynamically create a list of PDFs, and each row has a checkbox. You check the PDFs you want to download, whose ID get passed to a function to create the PDF. I store those PDF's in a list, which gets passed to the Zip function (DotNetZip). Problem is, when first generating a PDF, I get that error somewhere in the middle of creating it, about halfway through, when adding a new page in the PDF. Usually it's the same spot but occasionally it changes where it crashes. Could anyone look at my code and point out where I'm messing up?
protected void Download_PDF_Click(object sender, EventArgs e)
{
Response.Clear();
Response.BufferOutput = false;
HttpContext c = HttpContext.Current;
String archiveName = "Arhiva Inspectii.zip";
Response.ContentType = "application/zip";
Response.AddHeader("content-disposition", "filename=\"" + archiveName + "\"");
int nr_rows = tbl_inspectii.Rows.Count - 1;
foreach (String id_chbx in ID_Checkbox)
{
CheckBox chbx = tbl_inspectii.FindControl(id_chbx) as CheckBox;
String PDF_id = "";
if(chbx != null)
{
if(chbx.Checked)
{
PDF_id = chbx.ID.Replace("ChBx", string.Empty);
Create_PDF(PDF_id);
}
}
}
string destdir = Server.MapPath("~/Zip/") + archiveName;
using (ZipFile zip = new ZipFile())
{
zip.AddFiles(PDF_list, destdir);
zip.Save(destdir);
}
}
protected byte[] Create_PDF(String id_insp_max)
{
using (MemoryStream ms = new MemoryStream())
{
Document brosura = new Document(PageSize.A4);
brosura.SetMargins(40, 40, 40, 40);
PdfWriter wri = PdfWriter.GetInstance(brosura, ms);//new FileStream(Server.MapPath("Pdf/") + titlu_pdf + ".pdf", FileMode.Create)
HttpContext.Current.Response.AppendHeader("Content-Disposition", "inline; filename=\"" + titlu_pdf + ".pdf\"");
PdfWriter.GetInstance(brosura, HttpContext.Current.Response.OutputStream);
brosura.Open();
//lots of SQL, and brosura.Add();
//at some point, a brosura.Add() has the error halfway through the pdf
brosura.Close();
PDF_list.Add(titlu_pdf);
wri.Close();
return ms.ToArray();
}
}
Try to move the Response block after you closed the Document.
And try to add Response.End();
And why are you return the Array in Create_PDF but does not using it?

How to fix zip file corrupt error while downloading large files with Ionic-zip in c#

Getting error file corrupt error when downloading large files using Ionic.zip in c#. When user extracts that file file corrupt is being shown. When i am doing same with smaller no of files than it is working fine. Even it is not giving any error while creating zip files. I am creating zip file of existing pdf files which are added in one zip files. There may be 5 files or may 1000 files of minimum 10 MB each.
I have tried with threshold and all other options provided on google, but didn't find any solutions.
using (ZipFile zip = new ZipFile())
{
zip.AlternateEncodingUsage = ZipOption.AsNecessary;
zip.CompressionLevel = Ionic.Zlib.CompressionLevel.Level9;
//zip.AddDirectoryByName("Files");
for (int i = 0; i < dt.Rows.Count; i++)
{
filePath = Convert.ToString(dt.Rows[i]["filePath"]);
fileIds.Add(Convert.ToInt32(dt.Rows[i]["fileid"]));
string fileFullName = Convert.ToString(dt.Rows[i]["fileName"]);
string fName = Convert.ToString(dt.Rows[i]["fileName"]).Split('_')[1];
//ExceptionLogging c1 = new ExceptionLogging("filePath = " + filePath + " fileFullName = " + fileFullName +
// " fName = " + fName);
//c1.ErrorLog(HttpContext.Current.ApplicationInstance.Server.MapPath("~/Logs/"));
if (!fileNamesList.Contains(fileFullName.Split('_')[0]))
{
//ExceptionLogging c2 = new ExceptionLogging("In if condition -- filePath = " + filePath);
//c2.ErrorLog(HttpContext.Current.ApplicationInstance.Server.MapPath("~/Logs/"));
zip.AddFile(filePath, "Files");
fileNamesList.Add(fileFullName.Split('_')[0]);
}
else
{
filePath = filePath.Substring(0, filePath.Length - 4) + "_" + fName;
//filePath = filePath.Split('.')[0] + "_" + fName;
zip.AddFile(filePath, "Files");
fileNamesList.Add(fileFullName);
//ExceptionLogging c3 = new ExceptionLogging("In else condition -- filePath = " + filePath + " fileFullName = " + fileFullName);
//c3.ErrorLog(HttpContext.Current.ApplicationInstance.Server.MapPath("~/Logs/"));
}
//zip.AddFile(filePath, "Files");
}
Response.Clear();
Response.BufferOutput = false;
string zipName = String.Format("ZipFile-{0}.zip", DateTime.Now.ToString("yyyy-MMM-dd-HHmmss"));
Response.ContentType = "application/zip";
Response.AddHeader("content-disposition", "attachment; filename=" + zipName);
zip.Save(Response.OutputStream);
//Response.End();
HttpContext.Current.ApplicationInstance.CompleteRequest();
}
I should be able to download large files inside zip.
My explanation needs more space than a comment:
On x32 platforms the usable ram limit for .Net is holding the program to compress files in larger sizes. Try switching to x64 temporarily and that might fix your problem.
I also suggest research about LOH (Large Object Heap) which knowing it will come in handy for you in future dealing with these kind of scenarios:
An article about LOH

Display or Download document from Ajax call in MVC C# Application

I am attempting to download an SSRS report from a MVC C# application. I have an HttpResponseBase object and am sending it back to the client to be displayed/downloaded by the user, however, when the response is sent back to the client, I am getting symbols only.
Can some one please help clarify what I am missing upon the success of the ajax call?
I have attempted to use an option which worked with some success, however, the URL is too long when selecting certain parameters.
My controller is as follows:
[HttpPost]
public ActionResult DownloadReportData(string reportName, string reportPath, string reportParams, string repID, string book, string exportFormat)
{
string extension = string.Empty;
string fileName = reportName + "_" + (book.Length > 0 ? "" + book + "_" : "") + repID;
Dictionary<string, string> dc = new Dictionary<string, string>();
if (reportParams.Length > 0)
{
string[] param = reportParams.Split(';');
int i = 0;
while (i < param.Length)
{
dc.Add(param[i].Split('=')[0], param[i].Split('=')[1]);
i += 1;
}
}
//PDF for pdf export, EXCEL for excel export
byte[] bytes = autil.Reporting.ReportsManager.GenerateReport(reportPath, dc, exportFormat);
Response.ClearContent();
if (exportFormat.ToLower() == "pdf")
{
Response.ContentType = "application/pdf";
extension = ".pdf";
//Response.AppendHeader("Content-Disposition", "inline;filename=" + fileName + "" + extension + "");
Response.AppendHeader("Content-Disposition", "attachment;filename=" + fileName + "" + extension + "");
}
else if (exportFormat.ToLower() == "excel")
{
//Response.ContentType = "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet";
Response.ContentType = "application/vnd.ms-excel";
extension = ".xls";
Response.AppendHeader("Content-Disposition", "attachment;filename=" + fileName + "");
}
//Response.AppendHeader("Content-Disposition", "inline;filename=" + fileName + "" + extension + "");
Response.BufferOutput = true;
Response.AddHeader("Content-Length", bytes.Length.ToString());
Response.BinaryWrite(bytes);
Response.End();
//return null;
return Json(Response);
}
My view is as follows:
<div id="target"></div>
My javascript (ajax call) is as follows:
<script>
$.ajax({
type: 'POST',
url: '#Url.Action("DownloadReportData", "Reports")',
data:
{
reportName: reportName,
reportPath: reportPath,
reportParams: reportParams,
book: bookCode,
exportFormat: exportType
}
, success: function (data) {
$("#target").append($("<iframe>", {
srcdoc: data
}));
if (data.error == "none") {
alert("success" + data);
}
}
});
</script>
I am expecting either a downloaded version of the report or a prompt to Open (inline) or Save As to appear once the call is completed.
I am currently experiencing the following to be displayed:
%PDF-1.3 1 0 obj [/PDF /Text /ImageB /ImageC /ImageI] endobj 5 0 obj << /Length 1968 /Filter /FlateDecode >> stream x��[]o7}G��DZ��{�7��REi�H�Z�!�R�]�I������kdz��i#D���{αϽ���9��7h��|5�SM6�Y��Ҍt�t�J���4�DkC�$����9������.{�����y�� =����'�������Q�j ���]��]^����E���gG�^M�c�ʨ��/�A(�<�����a��"�>y�����b/��Ś�
I faced the same issue when I was trying to download excel from my ajax call. After many days I got the answer that you can't (I read it somewhere on SO). So I converted my ajax call to this
<div class="col-md-3">
#Html.ActionLink("Export Report", "ExportExcel", "Training",
new { }, new { #class = "btn btn-danger" })
</div>
and after that my code worked. You might have to make a few changes in order for this to work. I hope this help.

Creating a dialog for saving a csv file with C# and asp.net

Within my code I have an asp repeater and I wish to allow users to export the data from this to a csv file. Exporting to a csv works fine but when I wish to show a dialog box for users to choose where to save to nothing happens. I have went through several different solutions that apparently work but when I run them in my code nothing happens and I can not figure out why. This is my code at the moment:
protected void exportCSV_Click(object sender, EventArgs e)
{
try
{
string FilePath = Server.MapPath("~") + "\\test.csv";
StringBuilder columnbind = new StringBuilder();
foreach (Control item in rpt_bookings.Items)
{
Literal row1 = (Literal)item.FindControl("ltl_bookingemail");
Literal row2 = (Literal)item.FindControl("ltl_bookingphone");
Literal row3 = (Literal)item.FindControl("ltl_bookingcost");
string fullRow = row1.Text.ToString() + "," + row2.Text.ToString() + "," + row3.Text.ToString();
columnbind.Append(fullRow);
columnbind.Append("\r\n");
}
//// Creates the file on server
File.WriteAllText(FilePath, columnbind.ToString());
string FileName = "test.csv";
System.Web.HttpResponse response = System.Web.HttpContext.Current.Response;
response.ClearContent();
response.Clear();
response.ContentType = "text/csv";
response.AddHeader("Content-Disposition", "attachment; filename=" + FileName + ";");
response.TransmitFile(FilePath);
response.Flush();
response.End();
//// Deletes the file on server
File.Delete(FilePath);
//response.End();
lblmsg.Text = "";
}
catch (Exception ex)
{
Console.Write(ex);
Debug.Write(ex);
lblmsg.Text = ex.Message;
lblmsg.Style.Add("color", "#c73939");
}
}
The csv is correctly created but nothing happens with the response. The code executes but nothing comes up on the screen at all. According to several other questions along the same lines this is the solution.
Try the following changes:
response.ContentType = "application/octet-stream";
response.AppendHeader("Content-Disposition","attachment; filename=" + Filename + ";");
response.TransmitFile( FilePath );
response.End();
Don't delete the file in the next line but in the finally block instead:
catch (Exception ex)
{
[..]
}
finally
{
File.Delete(FilePath);
}

How to force a download of a created file to a users computer c#

I am looking to allow a person to to export journal entries into a text file. I can create a file with all the data but rather strictly saving the file somewhere specific I want to allow a user to download and save the file where they want on their computer. How to I force a download of a file after I create it with StreamWriter. I currently have the following code:
string fileName = "Journal.txt";
using (StreamWriter journalExport = new StreamWriter(fileName))
{
foreach (JournalEntryView entry in journalEnteries)
{
//write each journal entery to file/document
journalExport.WriteLine(entry.timestamp + " - " + entry.author + " (" + entry.authorRole + ")");
journalExport.WriteLine(entry.text);
journalExport.WriteLine("");
journalExport.WriteLine("");
}
}
I am also trying to put this into an ActionResult and return the file.
EDIT:
The following code is my new current code and the direction I am looking to go in, but when I use an ActionLink to call this method, i just get redirected to a new page rather than downloading the file.
string fileName = "Journal.txt";
string filepath = ConfigurationManager.AppSettings["DocumentRoot"] + "\\" + id + "\\" + fileName;
using (StreamWriter journalExport = new StreamWriter(filepath))
{
foreach (JournalEntryView entry in journalEnteries)
{
//write each journal entery to file/document
journalExport.WriteLine(entry.timestamp + " - " + entry.author + " (" + entry.authorRole + ")");
journalExport.WriteLine(entry.text);
journalExport.WriteLine("");
journalExport.WriteLine("");
}
}
byte[] fileData = System.IO.File.ReadAllBytes(filepath);
string contentType = MimeMapping.GetMimeMapping(filepath);
var cd = new System.Net.Mime.ContentDisposition
{
FileName = fileName,
Inline = true,
};
Response.AppendHeader("Content-Disposition", cd.ToString());
return File(fileData, contentType);
This might be what you are looking for:
public ActionResult GetFile()
{
...processing stuff...
return File("/files/file.pdf", "application/pdf");
//or
return File("/files/file.pdf", "application/force-download", "donwloadname.pdf");
}

Categories

Resources