Answered by:
Create PDF File for each record, C# MVC Ajax

Question
-
User-544325736 posted
Hello All,
I currently get a list of data selected by checkboxes.
I'm turning the records into a byte[] and inserting it into a .rdlc report.
I currently have it so my program creates a seperate PDF for each record this is done.
When I am in debug mode and I watch it, it creates each file it takes the correct byte[] for each record and inserts it into the rdlc document.
When I open the file though each file has the same content, each file should have its own records content.
Each should have its own content because it takes the correct byte[] but they are all the same.
Here is what I have
JavaScript and Ajax [Gets selected checkboxes and sents them to the controller]
$('#btnGetChecksz').on('click', function () { var arrChkBoxes = []; var arrSelectedQIDs = []; // Turn all selected checkbox T/F values into QuoteIDs $("input:checked").each(function (index, value) { arrChkBoxes.push($(value).val()); }); // Push all QuoteIDs into new array $.each(arrChkBoxes, function (key, value) { if (IsPositiveInteger(value)) { arrSelectedQIDs.push(value); } }); $.ajax({ type: "GET", url: "/Service/ExportReport/", contentType: "application/json; charset=utf-8", traditional: true, data: { "quoteIDs": arrSelectedQIDs }, success: function (data) { //alert("success"); window.location = '/Service/DownloadReportPDF?mimeType=' + data; }, error: function (request, status, error) { alert("error " + request.responseText); } }); });
C# MVC Controller
(Turns the IDs into a list of records and turns the list into each byte[] for rdlc report)
public ActionResult ExportReport(int[] quoteIDs) { List<byte[]> lstBytes = new List<byte[]>(); List<string> lstFileNames = new List<string>(); List<ServiceQuote> lstQuotes = new List<ServiceQuote>(); //var tstparam = ''; // servicequote same fields as 'Service_Fields' //for(int i=0; i<quoteIDs.Length-1; i++) //{ var quote = context.ServiceQuotes.Where(x => x.QuoteID == quoteIDs[i]).fi } if (quoteIDs != null) { string command = "PDF"; string reportType = command; string mimeType = "", encoding = "", fileNameExtension = ""; foreach (var qid in quoteIDs) { var quote = context.ServiceQuotes.Where(x => x.QuoteID == qid).FirstOrDefault(); lstQuotes.Add(quote); LocalReport localReport = new LocalReport() { ReportPath = Server.MapPath("~/ReportForms/VirtualService3.rdlc") }; ReportDataSource reportDataSource = new ReportDataSource("Service_Fields", lstQuotes); localReport.DataSources.Add(reportDataSource); string deviceInfo = "<DeviceInfo>" + " <OutputFormat>" + reportType + "</OutputFormat>" + " <PageWidth>8.5in</PageWidth>" + " <PageHeight>11in</PageHeight>" + " <MarginTop>0in</MarginTop>" + " <MarginLeft>0in</MarginLeft>" + " <MarginRight>0in</MarginRight>" + " <MarginBottom>0in</MarginBottom>" + "</DeviceInfo>"; Warning[] warnings; string[] streams; byte[] renderedBytes = localReport.Render(reportType, deviceInfo, out mimeType, out encoding, out fileNameExtension, out streams, out warnings); lstBytes.Add(renderedBytes); lstFileNames.Add(qid.ToString()); //lstFileNames.Add(qid.ToString() + "." + fileNameExtension); //TempData["localR"] = localReport; } TempData["Data"] = lstBytes; TempData["File"] = lstFileNames; //TempData["localR"] = LocalReport //return new JsonResult() { Data = new { MimeType = mimeType } }; return Json(mimeType, JsonRequestBehavior.AllowGet); //return new JsonResult(JsonRequestBehavior.AllowGet) { Data = new { MimeType = mimeType } }; //return File(renderedBytes, mimeType); } return RedirectToAction("VirtualService"); } [HttpGet] public virtual ActionResult DownloadReportPDF(string mimeType) { if (TempData["Data"] != null) { List<byte[]> lstBytesArray = TempData["Data"] as List<byte[]>; List<string> lstNamesArray = TempData["File"] as List<string>; //LocalReport localReport = TempData["localR"] as LocalReport; int i = 0; foreach(byte[] bytes in lstBytesArray) { var tempPath = Path.GetTempPath(); using (FileStream stream = new FileStream(String.Format(tempPath + lstNamesArray[i] + "_{0}.pdf", DateTime.Now.ToString("yyyy-MM-dd-HHmmss")), FileMode.Create)) { stream.Write(bytes, 0, bytes.Length); } i++; } return RedirectToAction("VirtualService"); } else { return new EmptyResult(); } }
Wednesday, November 6, 2019 2:46 PM
Answers
-
User475983607 posted
Again, the code that creates the report does not make sense. Each iteration a new item is added to lstQuotes and is passed to the report data source. The first iteration will have one Id {1} then next iteration two {1, 2}, then {1, 2, 3} and {1, 2, 3, 4, n). I assume this cause the same report to run over and over. Are you sure the reports are unique?
List<byte[]> lstBytes = new List<byte[]>(); List<string> lstFileNames = new List<string>(); List<ServiceQuote> lstQuotes = new List<ServiceQuote>(); //var tstparam = ''; // servicequote same fields as 'Service_Fields' //for(int i=0; i<quoteIDs.Length-1; i++) //{ var quote = context.ServiceQuotes.Where(x => x.QuoteID == quoteIDs[i]).fi } if (quoteIDs != null) { string command = "PDF"; string reportType = command; string mimeType = "", encoding = "", fileNameExtension = ""; foreach (var qid in quoteIDs) { var quote = context.ServiceQuotes.Where(x => x.QuoteID == qid).FirstOrDefault(); lstQuotes.Add(quote); LocalReport localReport = new LocalReport() { ReportPath = Server.MapPath("~/ReportForms/VirtualService3.rdlc") }; ReportDataSource reportDataSource = new ReportDataSource("Service_Fields", lstQuotes);
I recommend taking a closer look at your code.
- Marked as answer by Anonymous Thursday, October 7, 2021 12:00 AM
Thursday, November 7, 2019 3:20 PM -
User-544325736 posted
I ended up creating a model to hold my data separately.
Here is what i did. I FINALLY GOT IT!!!! WOO00OO0TTT
[HttpGet] public virtual ActionResult DownloadAsZip(string mimeType) { if (TempData["Files"] != null) { List<ServiceFile> lstFiles = TempData["Files"] as List<ServiceFile>; byte[] bytearray = null; using (MemoryStream ms = new MemoryStream()) { // Creates the .zip using (ZipArchive archive = new ZipArchive(ms, ZipArchiveMode.Create, true)) { foreach (ServiceFile file in lstFiles) // iterate through each file { // Creates empty file and names it inside of .zip ZipArchiveEntry zipItem = archive.CreateEntry(file.FileName + file.Extension); // adds file to zipItem using (MemoryStream ms4file = new MemoryStream(file.FileBytes)) { using (Stream stream = zipItem.Open()) { ms4file.CopyTo(stream); } } } } bytearray = ms.ToArray(); } return File(bytearray, "application/zip"); } else { return new EmptyResult(); } } public ActionResult ExportFiles(int[] quoteIDs) { List<ServiceFile> lstFiles = new List<ServiceFile>(); if (quoteIDs != null) { string command = "PDF"; string reportType = command; string mimeType = "", encoding = "", fileNameExtension = ""; foreach (var qid in quoteIDs) { List<ServiceQuote> lstQuotes = new List<ServiceQuote>(); var quote = context.ServiceQuotes.Where(x => x.QuoteID == qid).FirstOrDefault(); lstQuotes.Add(quote); LocalReport localReport = new LocalReport() { ReportPath = Server.MapPath("~/ReportForms/VirtualService3.rdlc") }; ReportDataSource reportDataSource = new ReportDataSource("Service_Fields", lstQuotes); localReport.DataSources.Add(reportDataSource); string deviceInfo = "<DeviceInfo>" + " <OutputFormat>" + reportType + "</OutputFormat>" + " <PageWidth>8.5in</PageWidth>" + " <PageHeight>11in</PageHeight>" + " <MarginTop>0in</MarginTop>" + " <MarginLeft>0in</MarginLeft>" + " <MarginRight>0in</MarginRight>" + " <MarginBottom>0in</MarginBottom>" + "</DeviceInfo>"; Warning[] warnings; string[] streams; byte[] renderedBytes = localReport.Render(reportType, deviceInfo, out mimeType, out encoding, out fileNameExtension, out streams, out warnings); lstFiles.Add(new ServiceFile { Extension = "." + fileNameExtension, FileName = qid.ToString(), FileBytes = renderedBytes }); } TempData["Files"] = lstFiles; //return new JsonResult() { Data = new { MimeType = mimeType } }; return Json(mimeType, JsonRequestBehavior.AllowGet); //return File(renderedBytes, mimeType); } return RedirectToAction("VirtualService"); }
- Marked as answer by Anonymous Thursday, October 7, 2021 12:00 AM
Thursday, November 7, 2019 4:28 PM
All replies
-
User475983607 posted
The design is not going to work. It looks like you are trying to create several reports files and use HTTP to combine the results. That's not going to work. In HTTP you cannot download multiple files. You can zip the files then download the zipped file.
If you want a single report then create a report with sub reports. Basically move the report generation logic into the RDLC report.
Wednesday, November 6, 2019 3:14 PM -
User-544325736 posted
Ok, So its not possible to create a seperate PDF for each record in the list and display the records data on it?
Currently I can create the number of records with the correct file name for each record but all the PDFs have the exact same data.So you are saying I could create each record with the correct data I need as long as I put them all in a .zip file?
I dont need a single report for all the records.
I need each report to have its own records data on it.
If its really not possibly to create them without using a .zip what about this idea.
If I zip all the files (each rdlc report) in a zip file.
Could I in code unzip the file. Take each file in the zip and move it to a new location.
Wednesday, November 6, 2019 4:20 PM -
User-474980206 posted
you should explain better your goal. as you code is creating pdf reports, and writing to disk on the server, that should work. if the reports have the same data, there is bug in your code. but if you are writing the files to the server, I don't understand the two steps (save to temp, then write to server disk)
if the goal gold is display / download multiple pdfs in the browser, that is not directly supported. a browser request can only return one file. you can zip them up, but then the user gets a zip file, that they may need to unzip (depending on o/s) to see contents.
Wednesday, November 6, 2019 6:20 PM -
User-544325736 posted
At first I wanted to download multiple PDFs to the hard drive. one 1 of each record. Now with learning this cant be done this way I want to create 1 zip file and each PDF inside of the zip should return what the selected records were. I get multiple byte[]s one for each record selected. I also can create the multiple PDFs inside of the zip file. Each PDF file has the correct ID name of the selected record BUT now when i go to open each zip each pdf the data in the zip are the same. Here is my current method which creates the ZIP and takes the PDF Byte[]s from a TempData object. The zipping and creating the pdfs in the zip is where my issue currently lies. Somewhere in this method.
[HttpGet] public virtual ActionResult DownloadReportZip(string mimeType) { byte[] bytearray = null; if(TempData["Data"] != null) { List<byte[]> lstBytesArray = TempData["Data"] as List<byte[]>; List<string> lstNamesArray = TempData["File"] as List<string>; using(MemoryStream ms = new MemoryStream()) { // Creates the .zip using(ZipArchive archive = new ZipArchive(ms, ZipArchiveMode.Create)) { int i = 0; foreach(byte[] bytes in lstBytesArray) // iterate through each file { // Creates empty file and names it inside of .zip ZipArchiveEntry zipItem = archive.CreateEntry(lstNamesArray[i] + ".pdf"); // adds file to zipItem using (MemoryStream ms4file = new MemoryStream(bytes)) { using(Stream stream = zipItem.Open()) { ms4file.CopyTo(stream); } } } } bytearray = ms.ToArray(); } } else { return new EmptyResult(); } return File(bytearray, "application/zip"); }
Wednesday, November 6, 2019 11:03 PM -
User-474980206 posted
have you used the debugger to see if the list of bytes arrays has unique values?
Wednesday, November 6, 2019 11:20 PM -
User475983607 posted
The code that generates the report passes the same lstQuotes list to the data source where each iteration add a new ServiceQuote type to the list. That does not look right to me. I recommend using the Visual Studio debugger to verify your code is functioning as expected. Keep in mind, forum members cannot easily replicate your environment. It is up to you learn how to use the debugger and troubleshoot your code.
The redirect is a bit confusing as well. TempData lasts for one redirect and the code needs at least two to function. The whole design seems a bit overly engineered.
Wednesday, November 6, 2019 11:31 PM -
User-544325736 posted
Yes each byte[] is unique. So I know each file is getting its own byte[].
When I get to the success part of my ajax I go into DownloadReportZip()
In here ' List<byte[]> lstBytesArray = TempData["Data"] as List<byte[]>;' I get both of the unique byte arrays. Currently when I create the file in the zip it creates the same file over and over. Its not taking the next byte[] in the list to create the next file.
Thursday, November 7, 2019 2:43 PM -
User-474980206 posted
My guess is that the report render always uses the first data source, and all the reports are the same. Easy to verify with the debugger.
Thursday, November 7, 2019 3:12 PM -
User475983607 posted
Again, the code that creates the report does not make sense. Each iteration a new item is added to lstQuotes and is passed to the report data source. The first iteration will have one Id {1} then next iteration two {1, 2}, then {1, 2, 3} and {1, 2, 3, 4, n). I assume this cause the same report to run over and over. Are you sure the reports are unique?
List<byte[]> lstBytes = new List<byte[]>(); List<string> lstFileNames = new List<string>(); List<ServiceQuote> lstQuotes = new List<ServiceQuote>(); //var tstparam = ''; // servicequote same fields as 'Service_Fields' //for(int i=0; i<quoteIDs.Length-1; i++) //{ var quote = context.ServiceQuotes.Where(x => x.QuoteID == quoteIDs[i]).fi } if (quoteIDs != null) { string command = "PDF"; string reportType = command; string mimeType = "", encoding = "", fileNameExtension = ""; foreach (var qid in quoteIDs) { var quote = context.ServiceQuotes.Where(x => x.QuoteID == qid).FirstOrDefault(); lstQuotes.Add(quote); LocalReport localReport = new LocalReport() { ReportPath = Server.MapPath("~/ReportForms/VirtualService3.rdlc") }; ReportDataSource reportDataSource = new ReportDataSource("Service_Fields", lstQuotes);
I recommend taking a closer look at your code.
- Marked as answer by Anonymous Thursday, October 7, 2021 12:00 AM
Thursday, November 7, 2019 3:20 PM -
User-544325736 posted
So I tried to go back to Ionic.Zip and i get the same results. Both
System.IO.Compression; or Ionic.Zip; I cn create the .ZIP file. Each record in the zip is named correctly. quoteid.pdf each is unuque. BUT when I open the pdf record. The contents of both PDFs are the exact same.
/* Uses Ionic.Zip Library */ [HttpGet] public virtual ActionResult DownloadReportZip(string mimeType) { if (TempData["Data"] != null) { List<byte[]> lstBytesArray = TempData["Data"] as List<byte[]>; List<string> lstNamesArray = TempData["File"] as List<string>; using (ZipFile zip = new ZipFile()) { zip.AlternateEncodingUsage = ZipOption.AsNecessary; int i = 0; foreach (byte[] bytes in lstBytesArray) { zip.AddEntry(lstNamesArray[i]+".pdf", bytes); i++; } string zipName = String.Format("Zip_{0}.zip", DateTime.Now.ToString("yyyy-MM-dd-HHmmss")); using (MemoryStream stream = new MemoryStream()) { zip.Save(stream); return File(stream.ToArray(), "application/zip", zipName); } } } else { return new EmptyResult(); } }
OR
/* Uses System.IO.Compression Library */ [HttpGet] public virtual ActionResult DownloadReportZip(string mimeType) { if (TempData["Data"] != null) { byte[] bytearray = null; List<byte[]> lstBytesArray = TempData["Data"] as List<byte[]>; List<string> lstNamesArray = TempData["File"] as List<string>; using (MemoryStream ms = new MemoryStream()) { // Creates the .zip using (ZipArchive archive = new ZipArchive(ms, ZipArchiveMode.Create, true)) { int i = 0; foreach (byte[] bytes in lstBytesArray) // iterate through each file { // Creates empty file and names it inside of .zip ZipArchiveEntry zipItem = archive.CreateEntry(lstNamesArray[i] + ".pdf"); // adds file to zipItem using (MemoryStream ms4file = new MemoryStream(bytes)) { using (Stream stream = zipItem.Open()) { ms4file.CopyTo(stream); } } i++; } } bytearray = ms.ToArray(); } return File(bytearray, "application/zip"); } else { return new EmptyResult(); } }
Both produce the same result Unique pdf names but same content.
My byte[]s both have a different number one it byte[61504] and the other is byte[61520] When I pick 2 different records. This means they are different correct?
Thursday, November 7, 2019 3:21 PM -
User-474980206 posted
you need to compare the byte values
Thursday, November 7, 2019 3:57 PM -
User-544325736 posted
I ended up creating a model to hold my data separately.
Here is what i did. I FINALLY GOT IT!!!! WOO00OO0TTT
[HttpGet] public virtual ActionResult DownloadAsZip(string mimeType) { if (TempData["Files"] != null) { List<ServiceFile> lstFiles = TempData["Files"] as List<ServiceFile>; byte[] bytearray = null; using (MemoryStream ms = new MemoryStream()) { // Creates the .zip using (ZipArchive archive = new ZipArchive(ms, ZipArchiveMode.Create, true)) { foreach (ServiceFile file in lstFiles) // iterate through each file { // Creates empty file and names it inside of .zip ZipArchiveEntry zipItem = archive.CreateEntry(file.FileName + file.Extension); // adds file to zipItem using (MemoryStream ms4file = new MemoryStream(file.FileBytes)) { using (Stream stream = zipItem.Open()) { ms4file.CopyTo(stream); } } } } bytearray = ms.ToArray(); } return File(bytearray, "application/zip"); } else { return new EmptyResult(); } } public ActionResult ExportFiles(int[] quoteIDs) { List<ServiceFile> lstFiles = new List<ServiceFile>(); if (quoteIDs != null) { string command = "PDF"; string reportType = command; string mimeType = "", encoding = "", fileNameExtension = ""; foreach (var qid in quoteIDs) { List<ServiceQuote> lstQuotes = new List<ServiceQuote>(); var quote = context.ServiceQuotes.Where(x => x.QuoteID == qid).FirstOrDefault(); lstQuotes.Add(quote); LocalReport localReport = new LocalReport() { ReportPath = Server.MapPath("~/ReportForms/VirtualService3.rdlc") }; ReportDataSource reportDataSource = new ReportDataSource("Service_Fields", lstQuotes); localReport.DataSources.Add(reportDataSource); string deviceInfo = "<DeviceInfo>" + " <OutputFormat>" + reportType + "</OutputFormat>" + " <PageWidth>8.5in</PageWidth>" + " <PageHeight>11in</PageHeight>" + " <MarginTop>0in</MarginTop>" + " <MarginLeft>0in</MarginLeft>" + " <MarginRight>0in</MarginRight>" + " <MarginBottom>0in</MarginBottom>" + "</DeviceInfo>"; Warning[] warnings; string[] streams; byte[] renderedBytes = localReport.Render(reportType, deviceInfo, out mimeType, out encoding, out fileNameExtension, out streams, out warnings); lstFiles.Add(new ServiceFile { Extension = "." + fileNameExtension, FileName = qid.ToString(), FileBytes = renderedBytes }); } TempData["Files"] = lstFiles; //return new JsonResult() { Data = new { MimeType = mimeType } }; return Json(mimeType, JsonRequestBehavior.AllowGet); //return File(renderedBytes, mimeType); } return RedirectToAction("VirtualService"); }
- Marked as answer by Anonymous Thursday, October 7, 2021 12:00 AM
Thursday, November 7, 2019 4:28 PM