I have an multi threaded Application. One of the property of application is reporting.
User can take one year data day by day
I fetch the database, get the results to the List. Then use Excel (as com object).
Excel is opened and cell values are started to be added from the list.
While these processes are going suddenly I get this message:
Here is my code for excel reporting:
private void RNReportDensityStatistics(List<object[]> _PlateBasedDensityStaticticsList)
{
try
{
RNTakeReportButton.Enabled = false;
RNExcelApp = new RNExcel.Application();
RNExcelApp.Visible = false;
RNWorkBook = RNExcelApp.Workbooks.Add();
RNWorkSheet = (RNExcel.Worksheet)RNExcelApp.ActiveSheet;
RNExcelApp.DisplayAlerts = false;
RNProgressBar.Visible = true;
RNProgressBar.Minimum = 0;
RNProgressBar.Maximum = _PlateBasedDensityStaticticsList.Count;
RNProgressBar.Value = 0;
RNProgressBar.Step = 1;
RNExcelApp.Range["A2"].Value = GetGUIItemString(GUIItemIndex.RNReportDensityStatisticsAutoParkPlate);
RNExcelApp.Range["B2"].Value = GetGUIItemString(GUIItemIndex.RNReportDensityStatisticsAutoParkEntryTime);
RNExcelApp.Range["C2"].Value = GetGUIItemString(GUIItemIndex.RNReportDensityStatisticsAutoParkExitTime);
RNExcelApp.Range["D2"].Value = GetGUIItemString(GUIItemIndex.RNReportDensityStatisticsAutoParkCameraIP);
RNExcelApp.Range["E2"].Value = GetGUIItemString(GUIItemIndex.RNReportDensityStatisticsAutoParkSpaceNo);
RNWorkSheet.Columns[1].AutoFit();
RNWorkSheet.Columns[2].AutoFit();
RNWorkSheet.Columns[3].AutoFit();
RNWorkSheet.Columns[4].AutoFit();
RNWorkSheet.Columns[5].AutoFit();
var row = 2;
foreach (var DensityStatistics in _PlateBasedDensityStaticticsList)
{
row++;
RNWorkSheet.Cells[row, "A"] = DensityStatistics[4];
RNWorkSheet.Cells[row, "B"] = ConvertEpochToDateTime(Convert.ToUInt64(DensityStatistics[2]));
RNWorkSheet.Cells[row, "C"] = ConvertEpochToDateTime(Convert.ToUInt64(DensityStatistics[3]));
RNWorkSheet.Cells[row, "D"] = DensityStatistics[0];
RNWorkSheet.Cells[row, "E"] = DensityStatistics[1];
RNProgressBar.PerformStep();
}
RNWorkSheet.Columns[1].AutoFit();
RNWorkSheet.Columns[2].AutoFit();
RNWorkSheet.Columns[3].AutoFit();
RNWorkSheet.Columns[4].AutoFit();
RNWorkSheet.Columns[5].AutoFit();
string RNExcelReportPath = RNExcelReportPathStartingAdress
+ GetGUIItemString(GUIItemIndex.RNReportPathNameAsPlate)
+ RNPlateSearchTextBox.Text + " "
+ GetGUIItemString(GUIItemIndex.RNReportPathNameAsDensity)
+ ".xlsx";
RNWorkBook.SaveAs(RNExcelReportPath,
misValue,
RNExcelPassword,
misValue,
misValue,
misValue,
RNExcel.XlSaveAsAccessMode.xlExclusive,
misValue,
misValue,
misValue,
misValue,
misValue);
RNWorkBook.Close(true, misValue, misValue);
RNExcelApp.Application.Quit();
RNExcelApp.Quit();
RNReleaseObject(RNWorkSheet);
RNReleaseObject(RNWorkBook);
RNReleaseObject(RNExcelApp);
RNTakeReportButton.Enabled = true;
AddLog(LogIndex.RNReportDensityStatisticsSuc, RNExcelReportPath, string.Empty, string.Empty);
}
catch (Exception ex)
{
RNReleaseObject(RNWorkSheet);
RNReleaseObject(RNWorkBook);
RNReleaseObject(RNExcelApp);
AddException(ex.ToString());
RNTakeReportButton.Enabled = true;
AddLog(LogIndex.RNReportDensityStatisticsFail, string.Empty, string.Empty, string.Empty);
}
finally
{
RNReleaseObject(RNWorkSheet);
RNReleaseObject(RNWorkBook);
RNReleaseObject(RNExcelApp);
RNTakeReportButton.Enabled = true;
RNProgressBar.Value = _PlateBasedDensityStaticticsList.Count;
RNProgressBar.Update();
}
}
private void RNReleaseObject(object obj)
{
try
{
System.Runtime.InteropServices.Marshal.FinalReleaseComObject(obj);
if (System.Runtime.InteropServices.Marshal.AreComObjectsAvailableForCleanup())
{
System.Runtime.InteropServices.Marshal.CleanupUnusedObjectsInCurrentContext();
}
obj = null;
}
catch (Exception ex)
{
obj = null;
AddTrace("Unable to release the Object ");
AddException(ex.ToString());
}
finally
{
GC.Collect();
GC.WaitForPendingFinalizers();
GC.Collect();
GC.WaitForPendingFinalizers();
}
}
There is no need to use COM object for reporting. I solved my problem by not using com object to use excel for reporting.
There are different tools for reporting and using excel for it
Open XML SDK : http://www.microsoft.com/en-us/download/details.aspx?id=5124
Documentation http://msdn.microsoft.com/en-us/library/bb491088(v=office.14).aspx
If Open XML SDK syntax is hard for you then you can use: http://spreadsheetlight.com/
Documentation is very well and Vincent (http://spreadsheetlight.com/about/ ) is really helpful for your questions.
If your application does not require some kind of charts then you can use: http://closedxml.codeplex.com/
Both of spreadsheetlight and Closed XML are based on Open XML SDK and from my experience I do not any kind of disconnected contex problem.
If you need to protect your excel files you can use: http://dotnetzip.codeplex.com/
You have a password protected zipped xlsx file.
In consequence, you dont need to use COM object, interop services and Excel.Exe in your computer.
I wish the suggestions are helpful and thank you for all who developed SpreadSheetLight and Closed XML and Open XML
Related
Good day to Stackoverflow community,
I am in need of some expert assistance. I have an MVC4 web app that has a few rich text box fields powered by TinyMCE. Up until now the system is working great. Last week my client informed me that they want to export the data stored in Microsoft SQL to Excel to run custom reports.
I am able to export the data to excel with the code supplied. However it is exporting the data in RTF rather than Plain text. This is causing issues when they try to read the content.
Due to lack of knowledge and or understanding I am unable to figure this out. I did read that it is possible to use regex to do this however I have no idea how to implement this. So I turn to you for assistance.
public ActionResult ExportReferralData()
{
GridView gv = new GridView();
gv.DataSource = db.Referrals.ToList();
gv.DataBind();
Response.ClearContent();
Response.Buffer = true;
Response.AddHeader("content-disposition", "attachment; filename=UnderwritingReferrals.xls");
Response.ContentType = "application/ms-excel";
Response.AddHeader("Content-Type", "application/vnd.ms-excel");
Response.Charset = "";
Response.Cache.SetCacheability(HttpCacheability.NoCache);
StringWriter sw = new StringWriter();
HtmlTextWriter htw = new HtmlTextWriter(sw);
gv.RenderControl(htw);
Response.Output.Write(sw.ToString());
Response.Flush();
Response.End();
return RedirectToAction("Index");
}
I would really appreciate any assistance. and thank you in advance.
I have looked for solutions on YouTube and web forums with out any success.
Kind Regards
Francois Muller
One option you can perform is to massage the Data you write to the XML file.
For example, idenfity in your string and replace it with string.Empty.
Similarly can be replaced with string.Empty.
Once you have identified all the variants of the Rich Text HTML tags, you can just create a list of the Tags, and inside a for FOR loop replace each of them with a suitable string.
Did you try saving the file as .xslx and sending over to the client.
The newer Excel format might handle the data more gracefully?
Add this function to your code, and then you can invoke the function passing it in the HTML string. The return output will be HTML free.
Warning: This does not work for all cases and should not be used to process untrusted user input. Please test it with variants of your input string.
public static string StripTagsCharArray(string source)
{
char[] array = new char[source.Length];
int arrayIndex = 0;
bool inside = false;
for (int i = 0; i < source.Length; i++)
{
char let = source[i];
if (let == '<')
{ inside = true; continue; }
if (let == '>') { inside = false; continue; }
if (!inside) { array[arrayIndex] = let; arrayIndex++; }
}
return new string(array, 0, arrayIndex);
}
So I managed to resolve this issue by changing the original code as follow:
As I'm only trying to convert a few columns, I found this to be working well. This will ensure each records is separated by row in Excel and converts the Html to plain text allowing users to add column filters in Excel.
I hope this helps any one else that has a similar issue.
GridView gv = new GridView();
var From = RExportFrom;
var To = RExportTo;
if (RExportFrom == null || RExportTo == null)
{
/* The actual code to be used */
gv.DataSource = db.Referrals.OrderBy(m =>m.Date_Logged).ToList();
}
else
{
gv.DataSource = db.Referrals.Where(m => m.Date_Logged >= From && m.Date_Logged <= To).OrderBy(m => m.Date_Logged).ToList();
}
gv.DataBind();
foreach (GridViewRow row in gv.Rows)
{
if (row.Cells[20].Text.Contains("<"))
{
row.Cells[20].Text = Regex.Replace(row.Cells[20].Text, "<(?<tag>.+?)(>|>)", " ");
}
if (row.Cells[21].Text.Contains("<"))
{
row.Cells[21].Text = Regex.Replace(row.Cells[21].Text, "<(?<tag>.+?)(>|>)", " ");
}
if (row.Cells[22].Text.Contains("<"))
{
row.Cells[22].Text = Regex.Replace(row.Cells[22].Text, "<(?<tag>.+?)(>|>)", " ");
}
if (row.Cells[37].Text.Contains("<"))
{
row.Cells[37].Text = Regex.Replace(row.Cells[37].Text, "<(?<tag>.+?)(>|>)", " ");
}
if (row.Cells[50].Text.Contains("<"))
{
row.Cells[50].Text = Regex.Replace(row.Cells[37].Text, "<(?<tag>.+?)(>|>)", " ");
}
}
Response.ClearContent();
Response.Buffer = true;
Response.AddHeader("content-disposition", "attachment; filename=Referrals " + DateTime.Now.ToString("dd/MM/yyyy") + ".xls");
Response.ContentType = "application/ms-excel";
Response.ContentEncoding = System.Text.Encoding.UTF8;
Response.AddHeader("Content-Type", "application/vnd.ms-excel");
Response.Charset = "";
Response.Cache.SetCacheability(HttpCacheability.NoCache);
StringWriter sw = new StringWriter();
HtmlTextWriter htw = new HtmlTextWriter(sw);
gv.RenderControl(htw);
//This code will export the data to Excel and remove all HTML Tags to pass everything into Plain text.
//I am using HttpUtility.HtmlDecode twice as the first instance changes null values to "Â" the second time it will run the replace code.
//I am using Regex.Replace to change the headings to more understandable headings rather than the headings produced by the Model.
Response.Write(HttpUtility.HtmlDecode(sw.ToString())
.Replace("Cover_Details", "Referral Detail")
.Replace("Id", "Identity Number")
.Replace("Unique_Ref", "Reference Number")
.Replace("Date_Logged", "Date Logged")
.Replace("Logged_By", "File Number")
.Replace("Date_Referral", "Date of Referral")
.Replace("Referred_By", "Name of Referrer")
.Replace("UWRules", "Underwriting Rules")
.Replace("Referred_To", "Name of Referrer")
);
Response.Flush();
Response.End();
TempData["success"] = "Data successfully exported!";
return RedirectToAction("Index");
}
I have this application in C# on VS2012, in which I need to generate Crystal Report 13.0.x. This application has been running fine for last 2 years or so . Recently did some addons and after that its giving error
Load Report Fail
However strange thing is that , in a day around 100 times this Crystal report is generated and in between it gives out that error. After the whole application has to be exited and then it works fine too. Because of this I am not abel to replicate the error at me end.
Here my code:
public partial class ChangeOrderList : Form
{
ConnectionClass connectionclass = new ConnectionClass();
NewOrderBL NObl = new NewOrderBL();
DailySalesReportBL DSRbl = new DailySalesReportBL();
public ChangeOrderList()
{
InitializeComponent();
}
private void ChangeOrderList_Load(object sender, EventArgs e)
{
/////////////////////////To count Lunch Buffet///////////////////
DataTable dtlb = DSRbl.selectBuffet(DateTime.Today.Date.ToString(), DateTime.Today.Date.ToString());
string date = dtlb.Rows[0][0].ToString();
////////////////////////////////////////////////////////////////
try
{
string sqlqry = "Select KOTNo,TableNo,WaiterName,ItemCode,ItemName,Quantity,Status,Foodtype from tblOrderChange where KOTNo=#kotno and Quantity>'0.00' and (Category!='Appetizer' and Category!='Indian Breads' and Category!='Desserts' and Category!='Beverages' and Category!='Tandoori')";
SqlCommand cmd = new SqlCommand(sqlqry, connectionclass.con);
cmd.Parameters.AddWithValue("#kotno", NewOrderBL.KOTNo);
SqlDataAdapter adapter = new SqlDataAdapter(cmd);
DataSet1 ds = new DataSet1();
adapter.Fill(ds, "tblOrderChange");
if (ds.Tables["tblOrderChange"].Rows.Count == 0)
{
MessageBox.Show("No Data Found", this.Text, MessageBoxButtons.OK, MessageBoxIcon.Information);
}
if (deliverybl.order == "Delivery")
{
//PrintDelivery printorder = new PrintDelivery();
ChangeOrderdelivery printorder = new ChangeOrderdelivery();
printorder.SetDataSource(ds);
crystalReportViewer1.ReportSource = printorder;
System.Drawing.Printing.PrintDocument printDocument = new System.Drawing.Printing.PrintDocument();
printorder.PrintOptions.PrinterName = printDocument.PrinterSettings.PrinterName;
printorder.PrintOptions.PrinterName = "EPSON TM-U220 Receipt";
printorder.PrintToPrinter(1, false, 0, 0);
}
else
{
crystalReportViewer1.RefreshReport();
ParameterFields paramFields = new ParameterFields();
ParameterField paramField = new ParameterField();
ParameterDiscreteValue paramDiscreteValue = new ParameterDiscreteValue();
paramField.Name = "LBqty";
paramDiscreteValue.Value = date;
paramField.CurrentValues.Add(paramDiscreteValue);
paramFields.Add(paramField);
PrintChangeOrderList printchangeorder = new PrintChangeOrderList();
printchangeorder.SetDataSource(ds);
printchangeorder.SetParameterValue("LBqty", date);
crystalReportViewer1.ReportSource = printchangeorder;
System.Drawing.Printing.PrintDocument printDocument = new System.Drawing.Printing.PrintDocument();
printchangeorder.PrintOptions.PrinterName = printDocument.PrinterSettings.PrinterName;
printchangeorder.PrintOptions.PrinterName = "EPSON TM-U220 Receipt";
printchangeorder.PrintToPrinter(1, false, 0, 0);
}
}
catch (Exception ex)
{
MessageBox.Show(ex.Message, this.Text, MessageBoxButtons.OK, MessageBoxIcon.Information);
}
finally { connectionclass.disconnect(); }
onlinebl.crystalreport = "";
this.DialogResult = DialogResult.OK;
}
private void btnExit_Click(object sender, EventArgs e)
{
onlinebl.crystalreport = "";
this.DialogResult = DialogResult.OK;
}
I have been banging my head for long . Every where I search it says about the path and I am not using the path anywhere so not able to understand where the fault is.
If you need any more info or the code please let me know. Thanks
Check your class:
<pre>
ChangeOrderdelivery printorder = new ChangeOrderdelivery();
printorder.SetDataSource(ds);
crystalReportViewer1.ReportSource = printorder;
this one has a report Path hidding i guess
ChangeOrderdelivery printorder = new ChangeOrderdelivery();
</pre>
I just deleted internet temp files and after that client has not yet complained about the error. So I am keeping an eye on it if it resolved the issue
This issue is driving me crazy. I am using
EPSON TM-T88V printer
to print , earlier it was fine one night OS upgraded to WIN10 and it went all crazy. I have a POS for a retaurant, so if I print a bill for a paricular table for the first time it prints with blank page after the bill hence its too long. But again I print it prints perfectly. Called EPSON and had some issues with test page so they some how fixed it , as there support were limited to only test page so left there. When I tried on POS its same.
Heres my code for printing
private void BillReceipt_Load(object sender, EventArgs e)
{
try
{
string sqlqry = "Select tb.TableNo,Pax,WaiterName,ItemCode,ItemName,Quantity,Amount,tb.BillNo,OrderType,RoundOffAmount as RoundOff, Discount,Gratuity,dues,Date1,tb.Time,ModeOfPayment,CardNo,CardHolderName,BankName,TotalAmount,VAT,ServiceTax,AmountPaid,Comments as comment,CustomerName,offeramount,DeliveryTax,Phoneno,Address From tblOrder o,tblBilling tb Where tb.KOTNo=#kotno and tb.KOTNo=o.KOTNo and o.KOTcancel='False'and o.Quantity>'0'and KOTCancel='False'";
SqlCommand cmd = new SqlCommand(sqlqry, connectionclass.con);
cmd.Parameters.AddWithValue("#kotno", NewOrderBL.KOTNo);
SqlDataAdapter adapter = new SqlDataAdapter(cmd);
DataSet3 ds = new DataSet3();
adapter.Fill(ds, "Billing");
if (ds.Tables["Billing"].Rows.Count == 0)
{
MessageBox.Show("No Data Found", this.Text, MessageBoxButtons.OK, MessageBoxIcon.Information);
}
if (deliverybl.order == "Delivery")
{
PrintBillDelivery printbilldelivery = new PrintBillDelivery();
printbilldelivery.SetDataSource(ds);
crystalReportViewer1.ReportSource = printbilldelivery;
System.Drawing.Printing.PrintDocument printDocument = new System.Drawing.Printing.PrintDocument();
printbilldelivery.PrintOptions.PrinterName = printDocument.PrinterSettings.PrinterName;
printbilldelivery.PrintOptions.PrinterName = "EPSON TM-T88V Receipt";//for JAPNA PC
printbilldelivery.PrintToPrinter(1, false, 0, 0);
}
else
{
PrintBillReceipt2 printbillreceipt2 = new PrintBillReceipt2();
printbillreceipt2.SetDataSource(ds);
crystalReportViewer1.ReportSource = printbillreceipt2;
System.Drawing.Printing.PrintDocument printDocument = new System.Drawing.Printing.PrintDocument();
printbillreceipt2.PrintOptions.PrinterName = printDocument.PrinterSettings.PrinterName;
printbillreceipt2.PrintOptions.PrinterName = "EPSON TM-T88V Receipt";//for JAPNA PC
printbillreceipt2.PrintToPrinter(1, false, 0, 0);
}
//////////////////////////////////////////////////
}
catch (Exception ex)
{
MessageBox.Show(ex.Message, this.Text, MessageBoxButtons.OK, MessageBoxIcon.Information);
}
finally { connectionclass.disconnect(); }
NewOrderBL.KOTNo = string.Empty;
onlinebl.crystalreport = "";
this.DialogResult = DialogResult.OK;
// this.Close();
}
If you need any other info do let me know.So please help. Thanks
I was able to solve the issue it was because of the WIN 10, once I was able to revert back to WIN 8 it worked as before.
Reason I think was crystal report version 13.x is not compatible with WIN 10(not sure though)
Here I coding for get each and every StudyUID(as string) from database to SqlDataReader,but i need to know how the reader value call to forloop execution.
Get to read each and every StudyUID for execution.Here is the code :.
public void automaticreport()
{
//string autsdyid="";
SqlConnection con = new SqlConnection(constr);
con.Open();
string autoquery = "Select StudyUID From StudyTable Where status='2'";
SqlCommand cmd = new SqlCommand(autoquery, con);
SqlDataReader rdr = cmd.ExecuteReader();
for()
{
//how to call each StudyUId from database through for loop
if (!this.reportchk)
{
Reportnew cf = new Reportnew();
ThreadPool.QueueUserWorkItem((WaitCallback)(o => cf.ReportRetrive(this, autsdyid, true)));
}
else
{
int num = (int)System.Windows.Forms.MessageBox.Show("Reports checking in progress, Please wait sometime and try again later", "OPTICS", MessageBoxButtons.OK, MessageBoxIcon.Asterisk);
}
con.Close();
}
Like #R.T and others have mentioned you can use the Read method on the data reader. Looking at your sample code you might want to refactor it slightly to meet more of the SOLID principles and make sure you're not leaking database connections
Here's an example of code that has been refactored a bit.
public void automaticreport()
{
foreach (var autsdyid in LoadStudyIdentifiers())
{
if (!this.reportchk)
{
Reportnew cf = new Reportnew();
ThreadPool.QueueUserWorkItem((WaitCallback)(o => cf.ReportRetrive(this, autsdyid, true)));
}
else
{
int num = (int)System.Windows.Forms.MessageBox.Show("Reports checking in progress, Please wait sometime and try again later", "OPTICS", MessageBoxButtons.OK, MessageBoxIcon.Asterisk);
}
}
}
private string[] LoadStudyIdentifiers()
{
var results = new List<string>();
// adding a using statement will close the database connection if there are any errors
// avoiding consuming the database connection pool
using (var con = new SqlConnection(constr))
{
conn.Open();
var autoquery = "Select StudyUID From StudyTable Where status='2'";
using (var cmd = new SqlCommand(autoquery, con))
{
SqlDataReader rdr = cmd.ExecuteReader();
while(rdr.Read())
{
results.Add(rdr.GetString(rdr.GetOrdinal("StudyUID")));
}
}
}
return results.ToArray();
}
Note: I wrote this in notepad so there is no guarantee it will compile but should give an indication as to how you could refactor your code.
if (rdr.HasRows)
{
while (rdr.Read())
{
Console.WriteLine(rdr.getString("columnName"));
}
}
You can use something like:
while (reader.Read())
{
string value = reader.getString("columnName");
}
You may use the while loop like this:
while (rdr.Read())
{
string s = rdr.GetString(rdr.GetOrdinal("Column"));
//Apply logic to retrieve here
}
I have developed a windows application to scan images.After the image is scanned i want to save it directly to the database not in local machine...The code which i have used is as follows
try
{
String str = string.Empty;
WIA.CommonDialogClass scanner;
ImageFile imageObject;
scanner = new CommonDialogClass();
imageObject = scanner.ShowAcquireImage
(WiaDeviceType.ScannerDeviceType,
WiaImageIntent.ColorIntent,
WiaImageBias.MinimizeSize,
ImageFormat.Jpeg.Guid.ToString("B"),
false,
true,
true);
str = DateTime.Now.ToString();
str = str.Replace("/", "");
str = str.Replace(":", "");
Directory.CreateDirectory("D:\\scanned1");
// MessageBox.Show(string.Format("File Extension = {0}\n
//\nFormat = {1}", imageObject.FileExtension, imageObject.FormatID));
imageObject.SaveFile(#"D:\scanned1\lel" + str + ".jpg");
MessageBox.Show("Scanning Done");
}
catch (Exception ex)
{
MessageBox.Show("Please check if the scanner is connected properly.");
}
Instead of saving it to D drive i want to save it to database.....How can i do it?Plz reply...
I've got no idea what "ImageFile" is really, but there should be a way to transform it into the byte array (byte[]). Afterwards you would need to insert that array to varbinary field in your sql.
something like this:
using(SqlCommand cmd = new SqlCommand("INSERT INTO MyTable (myvarbinarycolumn) VALUES (#myvarbinaryvalue)", conn))
{
cmd.Parameters.Add("#myvarbinaryvalue", SqlDbType.VarBinary, myarray.length).Value = myarray;
cmd.ExecuteNonQuery();
}
ofc sqlcommand should be opened and valid.
myarray is of type byte[]