Working with SubReports programmatically

7 posts, 0 answers
  1. Adam
    Adam avatar
    4 posts
    Member since:
    Apr 2013

    Posted 14 Apr 2013 Link to this post


    I'm using the ReportProcessor class in order to export reports in an HTML format progmmatically.  I have a couple of questions; I'm about at wit's end, here.

    I have a report which contains a sub report.  Each of these reports is encapsulated in a TRDX file.  I create an instance of the main report (let's call it MainReport), which is of type Telerik.Reporting.Report.  I get a reference to MainReport's DataSource property, which is a SqlDataSource, and I set the ConnectionString property to a connection string in my app.config file.  I then instantiate an InstanceReportSource and set the ReportDocument property to my MainReport object.  At this point, I can render the main report via the ReportProcessor.RenderReport method.  All is well and good so far.

    My problem is with the sub report.  What do I need to do to include it?  I've looked at the limited amount of documentation over and over but I simply cannot wrap my head around what I need to do.  Here's what almost works:

    I create an instance of the sub report the same way I'm instantiating MainReport (we'll call it SubReport).  I then Find() the sub report item within MainReport's Items collection, and after grabbing that reference, I set its ReportSource property to my SubReport instance.

    Here's the problem with that:  Apparently this way of doing things is obsolete.  I need to know how to do it correctly.  Also, I need SubReport.DataSource.ConnectionString to be the same as MainReport.DataSource.ConnectionString.  Additionally, there is a Crosstab item within the main report that apparently also needs a ConnectionString, even though the DataSource is the same as MainReport's DataSource.

    Here's some code snippets:

    //MainReport instantiation  (some code is hidden, but you should get the idea
    XmlReaderSettings xmlReaderSettings = new XmlReaderSettings();
    xmlReaderSettings.IgnoreWhitespace = true;
    ReportXmlSerializer serializer = new ReportXmlSerializer();
    XmlReader primaryReportXmlReader = XmlReader.Create(reportDefinition.PrimaryReport.TemplateLocation, xmlReaderSettings);
    _primaryReport = (Telerik.Reporting.Report)serializer.Deserialize(primaryReportXmlReader);
    SqlDataSource reportDataSource = (SqlDataSource)_primaryReport.DataSource;
    reportDataSource.ConnectionString = reportDefinition.ConnectionString;
    this._instanceReportSource.ReportDocument = _primaryReport;

    //We're using a custom class to define a "report definition", which contains data about sub reports,
    //so I'm looping through each sub report definition and instantiating it.
    foreach (CPSReport cpsSubReport in reportDefinition.SubReports)
        XmlReader xmlReader = XmlReader.Create(cpsSubReport.TemplateLocation, xmlReaderSettings);
        Telerik.Reporting.Report subReportInstance = (Telerik.Reporting.Report)serializer.Deserialize(xmlReader);
        SqlDataSource subReportDataSource = (SqlDataSource)subReportInstance.DataSource;
        subReportDataSource.ConnectionString = reportDefinition.ConnectionString;  //would be handy to automatically get from the main report
        //The following line is hardcoded for now because i've been experimenting.  The string "subReport1" would actually be defined in our custom report definition class.
        Telerik.Reporting.SubReport subReport = _primaryReport.Items.Find("subReport1", true).FirstOrDefault() as Telerik.Reporting.SubReport;
        subReport.ReportSource = subReportInstance;  //obsolete.  what's the right way to do this?

    Also, as I mentioned, in the rendered report, I get an error about the Crosstab connection string:

    An error has occurred while processing Table 'crosstab2': Unable to establish a connection to the database. Please, verify that your connection string is valid. In case you use a named connection string from the application configuration file, make sure the name is correct and the connection string settings are present in the configuration file of your application. ------------- InnerException ------------- Format of the initialization string does not conform to specification starting at index 0.

    Please help?  :)

  2. Chavdar
    Chavdar avatar
    898 posts

    Posted 18 Apr 2013 Link to this post


    The report source for the SubReport item should be again set via an InstanceReportSource as you do this for the main report. For example:

    Telerik.Reporting.InstanceReportSource instanceReportSource = new Telerik.Reporting.InstanceReportSource();
    instanceReportSource.ReportDocument = subReportInstance;
    subReport.ReportSource = instanceReportSource;

    The Report and the Crosstab item are different data items and as such they have different data sources. In your case you have to update the connection string for the CrossTab item as well.

    Here is a sample code snippet which iterates through all data items in the report and updates their connection string:

    foreach (Telerik.Reporting.DataItem dataItem in report.Items.Find(typeof(Telerik.Reporting.DataItem), true))
        Telerik.Reporting.SqlDataSource sqlDataSource = (Telerik.Reporting.SqlDataSource)dataItem.DataSource;
        sqlDataSource.ConnectionString = "...";

    Still, the best approach is to use named connection strings and specify them through the config file of the application.

    All the best,
    the Telerik team

    Have you tried the new visualization options in Telerik Reporting Q1 2013? You can get them from your account.

  3. Adam
    Adam avatar
    4 posts
    Member since:
    Apr 2013

    Posted 18 Apr 2013 Link to this post

    Got it.  Thank you!!  I guess reading the other dozen examples just wasn't enough.. I needed one more to make it click!  Heh..
  4. Michael Landy
    Michael Landy avatar
    15 posts
    Member since:
    Dec 2009

    Posted 09 May 2013 Link to this post

    I have the same situation.  In my case I have a main report with 2 sub reports.  I am using the processing engine to generate a PDF file.  I am now getting a PDF file with both subreports displayed.  However, the data displayed on the subreports is incorrect.  It is as if the data is not being sent to the report instance as the report is generated.

    The subreports share two parameters with the main report and a third parameter comes from the data in the main report.  I would have thought that my subreport would have been passed the data without my help.  It does not appear to be that way.

    I am so close...what am I missing?
  5. Adam
    Adam avatar
    4 posts
    Member since:
    Apr 2013

    Posted 10 May 2013 Link to this post

    Michael, I'm assuming the preview of your report in the designer is correct, in that the subreports are displaying the right data. Have you tried setting the shared parameters for each of your reports (the main report and the subreports)?
  6. Michael Landy
    Michael Landy avatar
    15 posts
    Member since:
    Dec 2009

    Posted 10 May 2013 Link to this post

    I figured out the issue.  The documentation is very poor surrounding the XML version of reports.  Here is what I have working and figured out from the various forums.

    If you want to dynamically load reports that may contain subreports, you need to do the following:

    1. Deserialize the main report
    2. Search the main report for any SubReport items
    3. For each SubReport, deserialize those reports
    4. Copy the parameter settings for the subreport
    5. Change the DB String of the subreport
    6. Create an InstanceReportSource for the subreport
    7. Set the main report subreport item to have a report source of the instance you just created
    8. Reapply all of the report parameters saved off in step 4

    Step 4 and 8 were missing.  After stepping through the code, I found that by attaching the subreport to the main report, the report parameters were being cleared.  So, by resetting them, everything began to work.
  7. Steve
    Steve avatar
    84 posts
    Member since:
    Aug 2013

    Posted 21 Jan 2014 Link to this post

    I have some of the items figured out (I think) but cannot figure out how to do steps 7 and 8.

    Here is what I have. Again, not sure it's correct.

    Protected Sub Page_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load
            If Not IsPostBack Then
                Dim crypto As Encryption.Crypto = New Encryption.Crypto("mystring")
                Dim conn As String = crypto.Decrypt(ConfigurationManager.ConnectionStrings("POS").ConnectionString)
                Dim report1 As Telerik.Reporting.Report = DeserializeReport(Server.MapPath("/Reports/Invoice.trdx"))
                TryCast(report1.DataSource, SqlDataSource).ConnectionString = conn
                Dim subreporta As Telerik.Reporting.SubReport = DirectCast(report1.Items.Find("subReport1", True)(0), SubReport)
                Dim instanceRS As Telerik.Reporting.UriReportSource = DirectCast(subreporta.ReportSource, UriReportSource)
                Dim uri As String = instanceRS.Uri
                Dim subparam As Telerik.Reporting.ParameterCollection = instanceRS.Parameters
                Dim subreport1 As Telerik.Reporting.Report = DeserializeReport(Server.MapPath("/Reports/" + uri))
                TryCast(subreport1.DataSource, SqlDataSource).ConnectionString = conn
                Dim irs As Telerik.Reporting.InstanceReportSource
                Dim srSource As Telerik.Reporting.InstanceReportSource
                srSource.ReportDocument = subreport1
        End if
    End Sub
     Private Function DeserializeReport(ByVal ReportPath As String) As Telerik.Reporting.Report
            Dim settings As New XmlReaderSettings()
            settings.IgnoreWhitespace = True
            Using xmlReader__1 As XmlReader = XmlReader.Create(ReportPath, settings)
                Dim xmlSerializer As New Telerik.Reporting.XmlSerialization.ReportXmlSerializer()
                Return DirectCast(xmlSerializer.Deserialize(xmlReader__1), Telerik.Reporting.Report)
            End Using
        End Function

    Anyone able to lend a hand on this, and correct any code that is wrong?

Back to Top