Tek-Tips is the largest IT community on the Internet today!

Members share and learn making Tek-Tips Forums the best source of peer-reviewed technical information on the Internet!

  • Congratulations Wanet Telecoms Ltd on being selected by the Tek-Tips community for having the most helpful posts in the forums last week. Way to Go!

Concurrency issue

Status
Not open for further replies.

MisterMo

Programmer
Mar 18, 2002
564
GB
Very new to C#

here is the code
Code:
using System;
using System.Collections.Generic;
using System.Text;
using System.Text.RegularExpressions;
using CrystalDecisions.CrystalReports.Engine;
using CrystalDecisions.Shared;
using System.Threading;
namespace Acumen.Reports
{
    public class CrystalReportGenerator
    {
        private ParameterDictionary _parms;

        public ParameterDictionary parms
        {
            get { return _parms; }
            set { _parms = value; }
        }

        public CrystalReportGenerator(string parameterString)
        {
            _parms = new ParameterDictionary(parameterString);
        }

        public CrystalReportGenerator(ParameterDictionary parms)
        {
            _parms = parms;
        }
        
        public void Process() 
        {
        LogonDescriptor logonDetails = new LogonDescriptor(parms);
        string reportName = String.Concat(parms["ReportPath"], parms["ReportName"]);
        string exportPath = String.Concat(parms["ExportPath"], parms["ExportName"]);
        string time = Regex.Replace(Regex.Replace(Regex.Replace(System.DateTime.Now.ToString(), ":", ""), "/", ""), " ", "");
        exportPath = Regex.Replace(exportPath,".pdf",time + ".pdf");
        Object thisLock = new Object();

        lock(thisLock)
        {
            ReportDocument reportDocument = new ReportDocument();
            try
            {
                
                reportDocument.Load(reportName);
                //set the logon parameters for the report
                reportDocument.SetDatabaseLogon(logonDetails.UserName, logonDetails.UserPassword, logonDetails.ServerName, logonDetails.DatabaseName);
                //set the logon parameters for possible subreports
                Sections sections = reportDocument.ReportDefinition.Sections;
                foreach (Section section in sections)
                {
                    ReportObjects reportObjects = section.ReportObjects;
                    foreach (ReportObject reportObject in reportObjects)
                    {
                        if (reportObject.Kind == ReportObjectKind.SubreportObject)
                        {
                            SubreportObject subreportObject = (SubreportObject)reportObject;
                            ReportDocument subReportDocument = subreportObject.OpenSubreport(subreportObject.SubreportName);
                            subReportDocument.SetDatabaseLogon(logonDetails.UserName, logonDetails.UserPassword, logonDetails.ServerName, logonDetails.DatabaseName);
                        }
                    }
                }
                //add the loop for the parameters input
                ParameterFields Fields = new ParameterFields();
                for (int i = 0; i < reportDocument.DataDefinition.ParameterFields.Count; i++)
                {
                    ParameterField paramField = new ParameterField();
                    ParameterDiscreteValue paramDiscreteValue = new ParameterDiscreteValue();
                    paramField.ParameterFieldName = reportDocument.DataDefinition.ParameterFields[i].ParameterFieldName;
                    paramDiscreteValue.Value = parms[reportDocument.DataDefinition.ParameterFields[i].ParameterFieldName];
                    paramField.CurrentValues.Add(paramDiscreteValue);
                    reportDocument.SetParameterValue(paramField.ParameterFieldName, paramDiscreteValue.Value);
                }
                //set the destination parameter for the export option
                DiskFileDestinationOptions fileOptions = new DiskFileDestinationOptions();
                fileOptions.DiskFileName = exportPath;
                reportDocument.ExportOptions.DestinationOptions = fileOptions;
                reportDocument.ExportOptions.UExportDestinationType = (int)ExportDestinationType.DiskFile;
                reportDocument.ExportOptions.UExportFormatType = (int)ExportFormatType.PortableDocFormat;
                reportDocument.Export();
            }
            catch
            {
                Console.WriteLine("What the hek's going on?");
            }
            finally
            {
                reportDocument.Close();
            }
            reportDocument.Dispose();
            }
        }
        
       
    }
}

this works fine but if I run more than 3 reports I get the error

Code:
A first chance exception of type 'System.IO.IOException' occurred in CrystalDecisions.CrystalReports.Engine.dll

I have had to put a lock which stops it from breaking but I would like to resolve it properly.

any help would be really appreciated

-Mo
 
Is this object being called multiple times on (possibly) different threads?

Because if it is, then the lock is required.

Another way of solving it would be to create a producer/consumer queue, where callers call a method that puts their request for a report onto a queue, and the code that actually creates the report will read from the queue. This disconnects the caller from the "engine", and allows the engine to work without any reentrancy problems.

The other possibilities are that Crystal is erroring (not uncommon), or that there's another process being spawned within Crystal that makes it non-reentrant.

Chip H.


____________________________________________________________________
If you want to get the best response to a question, please read FAQ222-2244 first
 
Thanks chiph I am already looking into queue but need to learn how because at the moment the code samples that I have found are too simplistic or do not seem to apply to my needs.

I would really appreciate if you could give me some pointers

-Mo
 
It's not so bad - you create a class with a static Queue object. You then write Add and Remove methods that wrap the Queue and Dequeue methods inside of C# lock statements.

You'll also want to write a class to be put onto the queue, which contains everything that the "engine" needs to do it's work (because it will run separately, and can't ask the caller for more info later).

When you want to do some work, you add an instance of your communications class (with everything filled out in it) to the queue using the Add method. Every now and again, your engine will call the Remove method. If it gets something back, it will do the work encapsulated in the communications object.

Chip H.


____________________________________________________________________
If you want to get the best response to a question, please read FAQ222-2244 first
 
Status
Not open for further replies.

Part and Inventory Search

Sponsor

Back
Top