1
votes

I made a code in C# to be used with Crystal Reports for Visual Studio, version 13.0.5.891, and Visual Studio 2010. It basically receives the name of a report file and a Dictionary with the parameters to pass to the .rpt file and shows the generated report on browser window. It's part of an ASP.NET MVC 3 application.

Here's the code:

    /// <summary>
    /// Shows the report
    /// </summary>
    /// <param name="reportName">Report name</param>
    /// <param name="parameters">Dictionary containing the pairs "key/value" of each parameter.</param>
    public static void ShowReport(string reportName, Dictionary<string, object> parameters)
    {
        if (!string.IsNullOrEmpty(reportName))
        {
            ReportDocument rd = new ReportDocument();
            CrystalDecisions.Shared.ConnectionInfo connection = new CrystalDecisions.Shared.ConnectionInfo();
            TableLogOnInfo tableLogin = new TableLogOnInfo();

            reportName += "_o.rpt"; // all .rpt files we use here have names ending with "_o"

            //Find and load the report.
            string strRptPath = Path.Combine(System.Web.HttpContext.Current.Server.MapPath("~/"), "Reports", reportName);
            rd.Load(strRptPath);

            //Get the application connection string to build de connection info object
            OracleConnectionStringBuilder builder = new OracleConnectionStringBuilder(ConnectionString.providerConnectionString());

            CrystalDecisions.ReportAppServer.DataDefModel.Table boTable =
                new CrystalDecisions.ReportAppServer.DataDefModel.Table();

            //boMainPropertyBag: These hold the attributes of the tables ConnectionInfo object
            PropertyBag boMainPropertyBag = new PropertyBag();
            //boInnerPropertyBag: These hold the attributes for the QE_LogonProperties
            //In the main property bag (boMainPropertyBag)
            PropertyBag boInnerPropertyBag = new PropertyBag();

            //Set the attributes for the boInnerPropertyBag
            boInnerPropertyBag.Add("Server", builder.DataSource);
            boInnerPropertyBag.Add("Trusted_Connection", "False");

            //Set the attributes for the boMainPropertyBag
            boMainPropertyBag.Add("Database DLL", "crdb_oracle.dll");
            boMainPropertyBag.Add("QE_DatabaseName", "");
            boMainPropertyBag.Add("QE_DatabaseType", "Oracle Server");
            //Add the QE_LogonProperties we set in the boInnerPropertyBag Object
            boMainPropertyBag.Add("QE_LogonProperties", boInnerPropertyBag);
            boMainPropertyBag.Add("QE_ServerDescription", "XE");
            boMainPropertyBag.Add("QE_SQLDB", "False");
            boMainPropertyBag.Add("SSO Enabled", "False");

            //Create a new ConnectionInfo object
            CrystalDecisions.ReportAppServer.DataDefModel.ConnectionInfo boConnectionInfo =
            new CrystalDecisions.ReportAppServer.DataDefModel.ConnectionInfo();
            //Pass the database properties to a connection info object
            boConnectionInfo.Attributes = boMainPropertyBag;
            //Set the connection kind
            boConnectionInfo.Kind = CrConnectionInfoKindEnum.crConnectionInfoKindCRQE;
            //**EDIT** Set the User Name and Password if required.
            boConnectionInfo.UserName = builder.UserID;
            boConnectionInfo.Password = builder.Password;
            //Pass the connection information to the table
            boTable.ConnectionInfo = boConnectionInfo;

            //Get the Database Tables Collection for your report
            CrystalDecisions.ReportAppServer.DataDefModel.Tables boTables;
            boTables = rd.ReportClientDocument.DatabaseController.Database.Tables;

            //For each table in the report:
            // - Set the Table Name properties.
            // - Set the table location in the report to use the new modified table
            int numtable = 0;
            foreach (CrystalDecisions.ReportAppServer.DataDefModel.Table table in boTables)
            {
                boTable.Name = table.Name;
                boTable.QualifiedName = builder.UserID + "." + table.Name;
                boTable.Alias = table.Name;

                rd.ReportClientDocument.DatabaseController.SetTableLocation(boTables[numtable], boTable);
                numtable++;
            }

            //Code for subreports.
            CrystalDecisions.ReportAppServer.Controllers.DatabaseController boDatabaseCtl = null;
            CrystalDecisions.ReportAppServer.DataDefModel.Database boDatabase = null;
            CrystalDecisions.ReportAppServer.ClientDoc.ISCDReportClientDocument boClientDoc = rd.ReportClientDocument;
            Strings subreportNames=boClientDoc.SubreportController.GetSubreportNames();
            for (int i = 0; i < subreportNames.Count; i++)
            {
                boDatabaseCtl = boClientDoc.SubreportController.GetSubreport(subreportNames[i]).DatabaseController;
                boDatabase = boDatabaseCtl.Database;
                boTables = boDatabase.Tables;

                numtable = 0;
                foreach (CrystalDecisions.ReportAppServer.DataDefModel.Table t in boTables)
                {
                    boTable.Name = t.Name;
                    boTable.QualifiedName = builder.UserID + "." + t.Name;
                    boTable.Alias = t.Name;

                    boDatabaseCtl.SetTableLocation(boTables[numtable], boTable);
                    numtable++;
                }
            }

            //Verify the database after adding substituting the new table.
            //To ensure that the table updates properly when adding Command tables or Stored Procedures.
            rd.VerifyDatabase();

            //Set the parameters.
            foreach (string key in parameters.Keys)
            {
                object value;
                if (parameters.TryGetValue(key, out value))
                    rd.SetParameterValue(key, value);
            }

            //Export(show) the report.
            rd.ExportToHttpResponse(ExportFormatType.PortableDocFormat, System.Web.HttpContext.Current.Response, false, "crReport");
            rd.Close();
            rd.Dispose();
        }
        else
        {
            // throws an exception saying the .rpt name was not informed
            throw new Exception(Idiomas.Atual.NomeRelatórioNãoInformado);   
        }
    }

It works fine when I use a report without subreports, or a report that has subreports which receive parameters from outside, but when I use subreports with subreport links it throws an exception with the message: Missing Parameter Values.

Any idea on what I'm missing here? Any help is greatly appreciated. Thanks!

2

2 Answers

0
votes

My situation differs from you in the higher level particulars, but I've been programmatically assigning parameters too. I haven't been using the SetParameterValue method, though.

Instead, I loop through the parameters collection in the data definition:

int intNumParameters = reportDoc.ParameterFields.Count;

for(int i = 0; i < intNumParameters; i++)
{
    if(!reportDoc.DataDefinition.ParameterFields[i].IsLinked())
    {
        ParameterValues pVals = new ParameterValues();
        ParameterDiscreteValue pdv = new ParameterDiscreteValue();
        pdv.Value = objValue;
        pVals.Add(pdv);
        reportDoc.DataDefinition.ParameterFields[i].ApplyCurrentValues(pVals);
    }
}

reportDoc.Export(expOpts);

I imagine you could probably do a lot of that inline, but this is just part of a little tool I whipped up for my own use. I probably should get the length of the DataDefinition.ParameterFields array instead of the ReportDocument.ParameterFields array, but it works regardless.

I don't know whether this will help you as I'm intentionally skipping over the linked parameters which appears to be at the root of your problem. But I can, at least, offer another way of assigning parameters. I will note that I too have subreports in the majority of my reports and haven't noticed any difference between processing those with them and those without.

Hope this helps :)

0
votes

if you want to continue using SetParameterValue ,just use this

reportDocument.SetParameterValue(string name,object value,string subreportname)

to pass a value to the specified parameter in subreport.

hope help