Optimizing reportviewer to not get outofmemory exception - c#

We have implemented a process using C# and reportviewer to create PDFs by the localreport.render method.
When we have to process a big file, say more than 20000 records, the process fails with outofmemory exception error. I know there may be lot of causes for this error but what I want to know is, if the below code is okay or if you expert can give me a better solution.
I have about 40 case statements each calling different .rdlc files and it is based on the type (I did not include all the case statements due to lack of space).
USP_Select_Batch_Address_To_Sort is a dataset defined in the solution executing a stored procedure accepting three parameters (in this case batch, run and sequence#).
So is this approach feasible? What other solution can you provide?
public static void GenerateIndividualPDFs(string batch, string run, MainDataSet1 DS, MainDataSet1TableAdapters.USP_Select_Batch_Address_To_SortTableAdapter Ta, BindingSource bs, int intStart = 0, int intEnd = 0, string strLetterType = "")
{
reportDataSource.Name = "DataSet1";
reportDataSource.Value = bs;
int count;
SqlDataAdapter adapter;
var batchinfo = new clsBatchInfo();
ReportViewer report = new ReportViewer();
report.LocalReport.DataSources.Add(reportDataSource);
if (!Directory.Exists(mstrFilePath + "\\" + batch + run))
{
DirectoryInfo di = Directory.CreateDirectory(mstrFilePath + "\\" + batch + run);
}
var DA = new clsGetBatchSort();
//this dataAdapter will print the full set
adapter = new SqlDataAdapter(DA.dsBatch_Sort(batch, run));
DataSet ds = new DataSet();
adapter.Fill(ds);
count = ds.Tables[0].Rows.Count;
int i = 0;
int LetterTypeID = 0;
report.ProcessingMode = ProcessingMode.Local;
foreach (DataRow dr in ds.Tables[0].Rows)
{
i++;
report.Clear();
Ta.ClearBeforeFill = true;
try
{
LetterTypeID = Convert.ToInt32(dr[2]);
switch (LetterTypeID)
{
case 1:
{
Ta.Fill(DS.USP_Select_Batch_Address_To_Sort, Convert.ToDecimal(batch), run, Convert.ToInt32(dr["MPresortID"]));
report.LocalReport.ReportEmbeddedResource = "ReportsApplication1.ABC.MAENG.rdlc";
ExportReport(Convert.ToInt32(dr["MPresortID"]), batch, run, report);
continue;
}
case 2:
{
Ta.Fill(DS.USP_Select_Batch_Address_To_Sort, Convert.ToDecimal(batch), run, Convert.ToInt32(dr["MPresortID"]));
report.LocalReport.ReportEmbeddedResource = "ReportsApplication1.ABC.MASPA.rdlc";
ExportReport(Convert.ToInt32(dr["MPresortID"]), batch, run, report);
continue;
}
catch (Exception ex)
{
clsEmail.EmailMessage("Error Batch " + batch + run, "clsGenerateLetters " + ex.Message);
continue;
//MessageBox.Show(ex.Message);
//return "";
}
}
}
private static void ExportReport(int PreSortID, string batch, string run, ReportViewer Report)
{
Report.RefreshReport();
Warning[] warnings;
string[] streamids;
string mimeType;
string encoding;
string filenameExtension;
string fmt = "00000000";
byte[] bytes = Report.LocalReport.Render(
"PDF", null, out mimeType, out encoding, out filenameExtension,
out streamids, out warnings);
string filename = mstrFilePath + "\\" + batch + run + "\\" + PreSortID.ToString(fmt) + ".PDF";
using (FileStream fs = new FileStream(filename, FileMode.Create))
{
fs.Write(bytes, 0, bytes.Length);
fs.Close();
}
Report.LocalReport.ReleaseSandboxAppDomain();
}

Related

ItextSharp modify takes time

I have a pdf template and I want to add an "option action" to that template, this should be done for all of the Recipients I have, which they're 4000.
This means I should end up with 4000 pdf files for each recipient.
But it takes a very long time, approx 500 files/12 mins.
Note: the template size is 340 KB
I built a windows service to do this job, and this is the code that does the job:
private static byte[] GeneratePdfFromPdfFile(byte[] file, string landingPage, string code)
{
try
{
using (var ms = new MemoryStream())
{
var reader = new PdfReader(file);
var stamper = new PdfStamper(reader, ms);
string _embeddedURL = "http://" + landingPage + "/Default.aspx?code=" + code + "&m=" + eventCode18;
PdfAction act = new PdfAction(_embeddedURL);
stamper.Writer.SetOpenAction(act);
stamper.Close();
reader.Close();
return ms.ToArray();
}
}
catch (Exception ex)
{
return null;
}
}
public static byte[] GenerateAttachment(AttachmentExtenstion type, string Contents, string FileName, string code, string landingPage, bool zipped, byte[] File = null)
{
byte[] finalVal = null;
try
{
switch (type)
{
case AttachmentExtenstion.PDF:
finalVal = GeneratePdfFromPdfFile(File, landingPage, code);
break;
case AttachmentExtenstion.WordX:
case AttachmentExtenstion.Word:
finalVal = GenerateWordFromDocFile(File, code, landingPage);
break;
case AttachmentExtenstion.HTML:
finalVal = GenerateHtmlFile(Contents, code, landingPage);
break;
}
return zipped ? _getZippedFile(finalVal, FileName) : finalVal;
}
catch (Exception ex)
{
return null;
}
finally
{
GC.Collect();
}
}
the GenerateAttachment Method is being called for each Recipient because the action is based on the recipient's id, and I'm using this approach to iterate through the List to speed up the process
Parallel.ForEach(listRecipients.AsEnumerable(),
new ParallelOptions { MaxDegreeOfParallelism = Environment.ProcessorCount * 2 },
(item) =>
{
File.WriteAllBytes(AppDomain.CurrentDomain.BaseDirectory + #"Attachments\" + group.Code + #"\" + item.Scenario.CampaignCode + #"\" + item.CMPRCode + "." + extension,
GenerateAttachment(_type, value, item.AttachmentName, item.CMPRCode, item.Scenario.LandingDomain, item.Scenario.AttachmentZip.Value));
});

How to create PDF Report with data from code in list form, not directly from database with Microsoft Report Viewer

I am using Microsoft.Report.Viewer for generate PDF in my ASP .NET WEB API application. So far when my report get the data directly from database, there is no problem. The problem is, when I try to create a report with subreport within and the subreport data is got from code in a list form, I didn't get the expected result. What I do is create a report with subreport from this tutorial. But when I generate the PDF, what I get is this message .
Here is my code :
My Web API to generate the PDF :
[Route("GeneratePDFForDailyProgram")]
[HttpGet]
[AllowAnonymous]
public async Task<IHttpActionResult> GeneratePDFForDailyProgram(int id) {
string guid = Guid.NewGuid().ToString();
string fileName = string.Concat("Booking_No" + Convert.ToString(id) + "_" + guid.ToUpper() + ".pdf");
string filePath = HttpContext.Current.Server.MapPath("~/Content/Temp/" + fileName);
string name = Request.RequestUri.GetLeftPart(UriPartial.Authority) + System.Configuration.ConfigurationManager.ConnectionStrings[System.Configuration.ConfigurationManager.AppSettings["CUSTOMPORT"]];
string name2 = Request.GetRequestContext().VirtualPathRoot;
List<TourDestination> destination = new List<TourDestination>();
TourTransactionSummaryViewModel summaryViewModel = new TourTransactionSummaryViewModel();
try {
//summaryViewModel = await CalcSummaryViewModel(transaction, summaryViewModel, db);
summaryViewModel.DailyPrograms = DailyProgram(id);
destination = TourDestination(summaryViewModel.DailyPrograms);
List < Movement > movementList = summaryViewModel.DailyPrograms.FirstOrDefault().Movements.ToList();
Reports.ReportGenerator.GeneratePDFForDailyProgram(summaryViewModel.DailyPrograms, destination, filePath);
//await Reports.ReportGenerator.GeneratePDFForMovement(movementList, filePath);
HttpResponseMessage result = null;
result = Request.CreateResponse(HttpStatusCode.OK);
result.Content = new StreamContent(new FileStream(filePath, FileMode.Open));
result.Content.Headers.ContentDisposition = new ContentDispositionHeaderValue("attachment");
result.Content.Headers.ContentDisposition.FileName = fileName;
result.Dispose();
string convertedFilePath = filePath.Replace(#"\\", #"\");
} catch (Exception ex) {
return BadRequest(ex.Message);
}
return Ok(name + name2 + "/Content/Temp/" + fileName);
}
As you can see from the code above, I use GeneratePDFForDailyProgram method to generate the PDF.
Here my GeneratePDFForDailyProgram method :
public static bool GeneratePDFForDailyProgram(TourTransactionSummaryViewModel.DailyProgram[] dailyPrograms, List<TourDestination> destination , string filePath) {
try {
string binPath = System.IO.Path.Combine(System.AppDomain.CurrentDomain.BaseDirectory, "bin");
var assembly = Assembly.Load(System.IO.File.ReadAllBytes(binPath + "\\TripPlannerAPI.dll"));
using (Stream stream = assembly.GetManifestResourceStream(DailyProgramReport)) {
var viewer = new ReportViewer();
viewer.LocalReport.EnableExternalImages = true;
viewer.LocalReport.LoadReportDefinition(stream);
Warning[] warnings;
string[] streamids;
string mimeType;
string encoding;
string filenameExtension;
viewer.LocalReport.SubreportProcessing += new Microsoft.Reporting.WebForms.SubreportProcessingEventHandler(LocalReport_SubreportProcessing);
viewer.LocalReport.DataSources.Add(new ReportDataSource("DailyProgram", dailyPrograms));
byte[] bytes = viewer.LocalReport.Render(
"PDF", null, out mimeType, out encoding, out filenameExtension,
out streamids, out warnings);
using (FileStream fs = new FileStream(filePath, FileMode.Create)) {
fs.Write(bytes, 0, bytes.Length);
fs.Flush();
}
stream.Flush();
}
} catch (Exception ex) {
return false;
}
return true;
}
To run the SubReport, I use the eventhandler code :
private static void LocalReport_SubreportProcessing(object sender, SubreportProcessingEventArgs e) {
DateTime movementDate = Convert.ToDateTime(e.Parameters[0].Values[0]);
TourTransactionsController controller = new TourTransactionsController();
var movement = controller.Movements();
List<Movement> movementList = new List<Movement>();
movementList.Add(new Movement {
Destination = "TEST",
MovementDescription = "TEST",
DateTime = Convert.ToDateTime("2017-09-25") //HARDCODE FOR TEST
});
e.DataSources.Clear();
e.DataSources.Add(new Microsoft.Reporting.WebForms.ReportDataSource() {
Name = "DSMovements",
Value = movementList
});
//throw new NotImplementedException();
}
What I did try :
Check the sub report name, and change it from report name to report file url. Still get the same message.
Generate the Sub Report directly, not from the main report. The subreport is successfully generated.
PS : When I debug my code, and put a breakpoint in my event handler LocalReport_SubreportProcessing the breakpoint is not hitting while debugging
My Questions are :
Why my breakpoint on the eventhandler is not hitting while debugging ?
Is it possible that eventhandler which is not hitting while debugging, could be the reason I got the message The subreport 'MovementReport' could not be
found at the specified location MovementReport.
Please verify that the subreport has been
published and that the name is correct. ?
Is there any other way for me to create a main report with data from db, and the subreport with data from code in list form ?
Any help is appreciated.

Dumping SQL table to .csv C#

I am trying to implement a script in my application that will dump the entire contents (for now, but I am trying to write the code so that I can easily customize it to only grab certain columns) of a sql db (running ms sql server express 2014) to a .csv file.
Here is the code I have written currently:
public void doCsvWrite(string timeStamp){
try {
//specify file name of log file (csv).
string newFileName = "C:/TestDirectory/DataExport-" + timeStamp + ".csv";
//check to see if file exists, if not create an empty file with the specified file name.
if (!File.Exists(newFileName)) {
FileStream fs = new FileStream(newFileName, FileMode.CreateNew);
fs.Close();
//define header of new file, and write header to file.
string csvHeader = "ITEM1,ITEM2,ITEM3,ITEM4,ITEM5";
using (FileStream fsWHT = new FileStream(newFileName, FileMode.Append, FileAccess.Write))
using(StreamWriter swT = new StreamWriter(fsWHT))
{
swT.WriteLine(csvHeader.ToString());
}
}
//set up connection to database.
SqlConnection myDEConnection;
String cDEString = "Data Source=localhost\\NAMEDPIPE;Initial Catalog=db;User Id=user;Password=pwd";
String strDEStatement = "SELECT * FROM table";
try
{
myDEConnection = new SqlConnection(cDEString);
}
catch (Exception ex)
{
//error handling here.
return;
}
try
{
myDEConnection.Open();
}
catch (Exception ex)
{
//error handling here.
return;
}
SqlDataReader reader = null;
SqlCommand myDECommand = new SqlCommand(strDEStatement, myDEConnection);
try
{
reader = myDECommand.ExecuteReader();
while (reader.Read())
{
for (int i = 0; i < reader.FieldCount; i++)
{
if(reader["Column1"].ToString() == "") {
//does nothing if the current line is "bugged" (containing no values at all, typically happens after reboot of 3rd party equipment).
}
else {
//grab relevant tag data and set the csv line for the current row.
string csvDetails = reader["Column1"] + "," + reader["Column2"] + "," + String.Format("{0:0.0}", reader["Column3"]) + "," + String.Format("{0:0.000}", reader["Column4"]) + "," + reader["Column5"];
using (FileStream fsWDT = new FileStream(newFileName, FileMode.Append, FileAccess.Write))
using(StreamWriter swDT = new StreamWriter(fsWDT))
{
//write csv line to file.
swDT.WriteLine(csvDetails.ToString());
}
}
}
}
}
catch (Exception ex)
{
//error handling here.
myDEConnection.Close();
return;
}
myDEConnection.Close();
}
catch (Exception ex)
{
//error handling here.
MessageBox.Show(ex.Message);
}
}
Now, this was working fine when I was using it with a 3rd party SQLite-based database, but the output I'm getting after modifing this to my MSSQL db looks something like this (ITEM1 is the primary key, a standard auto-incrementing ID-field):
ITEM1,ITEM2,ITEM3,ITEM4,ITEM5
1,row1_item2,row1_item3,row1_item4,row1_item5
1,row1_item2,row1_item3,row1_item4,row1_item5
1,row1_item2,row1_item3,row1_item4,row1_item5
1,row1_item2,row1_item3,row1_item4,row1_item5
1,row1_item2,row1_item3,row1_item4,row1_item5
1,row1_item2,row1_item3,row1_item4,row1_item5
2,row2_item2,row2_item3,row2_item4,row2_item5
2,row2_item2,row2_item3,row2_item4,row2_item5
2,row2_item2,row2_item3,row2_item4,row2_item5
2,row2_item2,row2_item3,row2_item4,row2_item5
2,row2_item2,row2_item3,row2_item4,row2_item5
3,row3_item2,row3_item3,row3_item4,row3_item5
3,row3_item2,row3_item3,row3_item4,row3_item5
3,row3_item2,row3_item3,row3_item4,row3_item5
3,row3_item2,row3_item3,row3_item4,row3_item5
....
So it seems that it writes several entries of the same row, where I would just like one single line each row. Any suggestions?
Thanks in advance.
edit: Thanks everyone for your answers!
The for loop isn't needed in the section below. Because it loops from 0 to FieldCount I assume the loop was originally meant to append the text from each column together but inside the loop there's a single line that concatenates the text and assigns it to csvDetails.
try
{
reader = myDECommand.ExecuteReader();
while (reader.Read())
{
for (int i = 0; i < reader.FieldCount; i++)
{
if(reader["Column1"].ToString() == "") {
//does nothing if the current line is "bugged" (containing no values at all, typically happens after reboot of 3rd party equipment).
}
else {
//grab relevant tag data and set the csv line for the current row.
string csvDetails = reader["Column1"] + "," + reader["Column2"] + "," + String.Format("{0:0.0}", reader["Column3"]) + "," + String.Format("{0:0.000}", reader["Column4"]) + "," + reader["Column5"];
using (FileStream fsWDT = new FileStream(newFileName, FileMode.Append, FileAccess.Write))
using(StreamWriter swDT = new StreamWriter(fsWDT))
{
//write csv line to file.
swDT.WriteLine(csvDetails.ToString());
}
}
}
}
}
Usually, we use specialy designed export/import utilites for dumping data.
However, if you have to implement you own routine I suggest decomposing.
private static IEnumerable<IDataRecord> SourceData(String sql) {
using (SqlConnection con = new SqlConnection(ConnectionStringHere)) {
con.Open();
using (SqlCommand q = new SqlCommand(sql, con)) {
using (var reader = q.ExecuteReader()) {
while (reader.Read()) {
//TODO: you may want to add additional conditions here
yield return reader;
}
}
}
}
}
private static IEnumerable<String> ToCsv(IEnumerable<IDataRecord> data) {
foreach (IDataRecord record in data) {
StringBuilder sb = new StringBuilder();
for (int i = 0; i < record .FieldCount; ++i) {
String chunk = Convert.ToString(record .GetValue(0));
if (i > 0)
sb.Append(',');
if (chunk.Contains(',') || chunk.Contains(';'))
chunk = "\"" + chunk.Replace("\"", "\"\"") + "\"";
sb.Append(chunk);
}
yield return sb.ToString();
}
}
Having SourceData and ToCsv you can easily implement
private static void WriteMyCsv(String fileName) {
var source = SourceData("SELECT * FROM table");
File.WriteAllLines(fileName, ToCsv(source));
}
You have a for loop which is looping over the fieldcount.
for (int i = 0; i < reader.FieldCount; i++)
I think it will work if you remove the loop as you don't need to iterate through the columns.
it happens because output placed inside for-loop
for (int i = 0; i < reader.FieldCount; i++)
and every record repeats FieldCount-times
Complete example. Verified working .NET 4.8, May 22. Code simplified for demo.
Why the DataTable ? Under circumstances it is useful. If you converting hundreds of files at once and multi threading - it works as large buffer + you can do pretty complex data mangling at the same time - should you need it.
UNFORTUNATELY - Microsoft trying to detect the column types and if your data not comply with the mechanism it ends with hard to correct errors. In that case use the second solution.
// Get the data from SQLite
SqliteConnection SQLiDataCon = new SqliteConnection(#"Data Source=c:\sqlite.db3");
SQLiDataCon.Open();
SqliteDataReader SQLiDtaReader = new SqliteCommand(#"SELECT * FROM stats;", SQLiDataCon).ExecuteReader();
// Load data to DataTable
DataTable csvTable = new DataTable();
csvTable.Load(SQLiDtaReader);
// Get "one" string with column names
string csvFields = #"""" + String.Join(#""",""",csvTable.Columns.Cast<DataColumn>().Select(dc => dc.ColumnName).ToArray()) + #"""";
// Prep "in memory the entire content of the CSV"
StringBuilder csvString = new StringBuilder();
// Write the header in
csvString.AppendLine(csvFields);
// Write the rows in
foreach (DataRow dr in csvTable.Rows)
{
csvString.AppendLine(#"""" + String.Join(#""",""", dr.ItemArray) + #"""");
}
// Save to file
StreamWriter csvFile = new StreamWriter(#"c:\stats.csv");
csvFile.Write(csvString);
Without DataTable.
// SQLITE
SqliteConnection SQLiDataCon = new SqliteConnection(#"Data Source=c:\sqlite.db3");
SQLiDataCon.Open();
StringBuilder csvString = new StringBuilder();
StreamWriter csvFile;
Object[] csvRow;
SqliteDataReader SQLiDtaReader = new SqliteCommand(#"SELECT * FROM sometable;", SQLiDataCon).ExecuteReader();
// CSV HEADER
csvString.AppendLine(#"""" + String.Join(#""",""", SQLiDtaReader.GetSchemaTable().AsEnumerable().Select(dr => dr.Field<string>("ColumnName")).ToArray<string>()) + #"""");
// CSV BODY
while (SQLiDtaReader.Read())
{
SQLiDtaReader.GetValues(csvRow = new Object[SQLiDtaReader.FieldCount]);
csvString.AppendLine(#"""" + String.Join(#""",""",csvRow ) + #"""");
}
// WRITE IT
csvFile = new StreamWriter(#"C:\somecsvfile.csv");
csvFile.Write(csvString);

Trying to download excel file from ssrs and using ClosedXML to modified, getting exception

Trying to download excel file from ssrs and using ClosedXML to modified, getting exception.
Following is my code, getting exception at exlWorkBook = new XLWorkbook(FilePath);
public ActionResult ExportToExcel(string VesselObjectId, string EnquiryID)
{
XLWorkbook exlWorkBook = null;
string FileName = "QuoteCompare_" + VesselObjectId + "_" + String.Format("{0:yyyyMMddHHmmss}", DateTime.Now) + ".xlsx";
string DirPath = Server.MapPath("~/App_Files/Seachef");
string FilePath = Path.Combine(DirPath, FileName);
string strTargetURL = GlobalParameters.SSRSBaseUrl + "/SeaChefReports/rptQuoteCompare&User_ID=" + CurrentUserData.UserId + "&P_ENQUIRY_HD_ID=" + EnquiryID + "&rc:LinkTarget=_blank&rc:Parameters=False&rs:Format=EXCELOPENXML&rs:ClearSession=true";
try
{
ReportViewer objReportViewer = new ReportViewer();
objReportViewer.ProcessingMode = ProcessingMode.Remote;
objReportViewer.ServerReport.ReportServerCredentials = new CustomReportCredentials(ConfigurationManager.AppSettings["ReportServerId"], ConfigurationManager.AppSettings["ReportServerPwd"], "BSM");
objReportViewer.ServerReport.Refresh();
SSRSWebClient client = new SSRSWebClient();
client.DownloadFileBinary(FilePath, strTargetURL);
if (new FileInfo(FilePath).Exists)
{
exlWorkBook = new XLWorkbook(FilePath);
var ws = exlWorkBook.Worksheet("rptQuoteCompare");
List<IXLCell> vendorsectionTotalCells = new List<IXLCell>();
List<IXLCell> vendorCategoryTotalCells = new List<IXLCell>();
ws.SheetView.FreezeRows(5);
ws.SheetView.FreezeColumns(7);
ws.Range(ws.FirstCell(), ws.LastCellUsed()).Style.Protection.Locked = true;
ws.Cell("A1").Value = EnquiryID;
//Doing Some more modifications
exlWorkBook.Style.Protection.Locked = true;
var protection = ws.Protect(BSMUiHelpers.SeachefSessionVariables.SeachefSessionData.ExcelPassword);
protection.SelectLockedCells = true;
protection.SelectUnlockedCells = true;
Stream objStream = new MemoryStream();
exlWorkBook.SaveAs(objStream);
objStream.Position = 0;
BinaryReader rdr = new BinaryReader(objStream);
byte[] fileData = rdr.ReadBytes((int)objStream.Length);
rdr.Close();
objStream.Close();
return File(fileData, "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet", FileName);
}
else
{
return Json("Export failed!");
}
}
catch (Exception ex)
{
bool rethrow = UserInterfaceExceptionHandler.HandleExcetion(ref ex, CurrentUserData.UserId.ToString(), "");
return Json("Export failed!" + ex.Message);
}
finally
{
if (exlWorkBook != null)
exlWorkBook.Dispose();
if (new FileInfo(FilePath).Exists)
System.IO.File.Delete(FilePath);
}
}
below is the Stack Trace
at ClosedXML.Excel.XLWorkbook.LoadCells(SharedStringItem[] sharedStrings, Stylesheet s, NumberingFormats numberingFormats, Fills fills, Borders borders, Fonts fonts, Dictionary`2 sharedFormulasR1C1, XLWorksheet ws, Dictionary`2 styleList, Cell cell, Int32 rowIndex)
at ClosedXML.Excel.XLWorkbook.LoadRows(Stylesheet s, NumberingFormats numberingFormats, Fills fills, Borders borders, Fonts fonts, XLWorksheet ws, SharedStringItem[] sharedStrings, Dictionary`2 sharedFormulasR1C1, Dictionary`2 styleList, Row row)
at ClosedXML.Excel.XLWorkbook.LoadSpreadsheetDocument(SpreadsheetDocument dSpreadsheet)
at ClosedXML.Excel.XLWorkbook.LoadSheets(String fileName)
at ClosedXML.Excel.XLWorkbook.Load(String file)
at ClosedXML.Excel.XLWorkbook..ctor(String file, XLEventTracking eventTracking)
at ClosedXML.Excel.XLWorkbook..ctor(String file)
at BSM.BSMPALv2.Web.Areas.Seachef.Controllers.QuotationComparisionController.ExportToExcel(String VesselObjectId, String EnquiryID) in d:\XXX\TestSource\XXXXXXX.XXXXXX\XXXXXXX.XXXX\XXXXXXXXXX\Areas\ModuleName\Controllers\QuotationComparisionController.cs:line 293

Multithreading RDLC report not refreshing

Gurus
We are developing a win forms application in .NET 4.0, that generate PDF reports using RDLC control. As the report generation takes lot of time, we decided to implement Parallel for each.. With the following code , it generates the PDF for first record after that, system just hangs.. Do help us...
public void generatereport()
{
button1.Enabled = false;
button4.Enabled = false;
DataTable dtBranch = new DataTable();
dtBranch = getBranchNo(); -- we might get around 300 rows here
try
{
Parallel.ForEach(dtBranch.AsEnumerable(), drow =>
{
// Shows the ReportData along with the branch code
reportdate = drow["reportdate"].ToString();
string branchName = drow["BranchNo"].ToString();
ProcessReport(branchName);
});
reportViewer2.Visible = false;
button1.Enabled = true;
button4.Enabled = true;
lblMsg.Text = "Branch Summary Generated at '" + #fullpath + "'";
}
catch (AggregateException e)
{
//Console.Write(e.Data + e.Message);
//Console.ReadLine();
}
}
private void ProcessReport(string branName)
{
if (reportViewer2.InvokeRequired)
{
ProcessReportCallBack d = new ProcessReportCallBack(ProcessReport);
Invoke(d, new object[] { branName });
}
else
{
log.Debug("branch" + DateTime.Now.ToString());
DataTable dt = new DataTable();
dt = getReportOrderNoBasedonBranchID(branName);//Get all the report order no as per the branch id
this.sp_getReportOrderNoTableAdapter.Fill(this.getRptNo.sp_getReportOrderNo, branName);
this.reportViewer2.LocalReport.SubreportProcessing += new Microsoft.Reporting.WinForms.SubreportProcessingEventHandler(this.reportViewer2_Subreport1);
this.reportViewer2.Clear();
this.reportViewer2.ProcessingMode = ProcessingMode.Local;
this.reportViewer2.LocalReport.ReportPath = #"Master.rdlc";
this.reportViewer2.Refresh();
Savepdf("reportViewer2", branName + "_" + reportdate);
}
}
In save PDF we are generating the PDF report..
byte[] bytes = null;
bytes = reportViewer2.LocalReport.Render(
"PDF", null, out mimeType, out encoding,
out extension,
out streamids, out warnings);
filename = BranchName + '_' + "Summary" + ".pdf";
using (FileStream fs = new FileStream(#fullpath + '\\' + filename, FileMode.Create))
{
fs.Write(bytes, 0, bytes.Length);
fs.Close();
}
bytes = null;
Kindly provide your feedback
you don't need a sample codes to Export to PDF, when the RDLC is already rendered to the ReportViewer try to find this icon from the ToolBars of ReportViewer Control:
EDIT:
Save RDLC reports as PDF programaticaly
public void Save(ReportViewer viewer, string savePath)
{
byte[] Bytes = viewer.LocalReport.Render("PDF", "", null, null, null, null, null);
using (FileStream Stream = new FileStream(savePath, FileMode.Create)) {
Stream.Write(Bytes, 0, Bytes.Length);
}
}

Categories

Resources