Subreports in the same directory as a master report are not found

1 Answer 24 Views
SubReport
Don
Top achievements
Rank 1
Don asked on 18 Mar 2025, 09:13 PM

I have a program that is installed in C:\Program Files (x86)\Qiagen\PGxUtils and I am using the code below to render reports by passing the full path of the report template to the function. This works fine when it is a single standalone report but when I try to use a report with subreports I get the following:

Could not find file 'C:\Program Files (x86)\Qiagen\PGxUtils\SubFinalReportV1_PatientDemographics.trdp'., 
Could not find file 'C:\Program Files (x86)\Qiagen\PGxUtils\SubFinalReportV1_Header.trdp'., 
Could not find file 'C:\Program Files (x86)\Qiagen\PGxUtils\SubFinalReportV1_PrescribingInsights.trdp'., 
Could not find file 'C:\Program Files (x86)\Qiagen\PGxUtils\SubFinalReportV1_RiskManagement.trdp'., 
Could not find file 'C:\Program Files (x86)\Qiagen\PGxUtils\SubFinalReportV1_Medication.trdp'., 
Could not find file 'C:\Program Files (x86)\Qiagen\PGxUtils\SubFinalReportV1_TestResult.trdp'.

 

Reading the online documentation this seems to be by design but I need to know how to work around it in order to use subreports.

using Telerik.Reporting;
using System.Text.Json.Nodes;
using System.Text.Json;

namespace PdfReportBuilder
{
    public static class TelerikReportBuilder
    {
        public static ReportSource GetReportSource(string reportPath, JsonNode jsonNode)
        {
            var reportPackager = new ReportPackager();
            using (var sourceStream = System.IO.File.OpenRead(reportPath))
            {
                Report report = (Report)reportPackager.UnpackageDocument(sourceStream);
                var jsonDataSources = report.GetDataSources().OfType<JsonDataSource>();
                foreach (var jsonDataSource in jsonDataSources)
                {
                    jsonDataSource.Source = jsonNode.ToJsonString(new System.Text.Json.JsonSerializerOptions { WriteIndented = true });
                    // This proves that Source can be assigned a json string, assigning a JsonNode doesn't work.
                    // JsonNode? tmp = JsonNode.Parse((jsonDataSource.Source as string)!);
                    // jsonDataSource.Source = tmp.ToJsonString(new System.Text.Json.JsonSerializerOptions { WriteIndented = true });
                }
                return new InstanceReportSource
                {
                    ReportDocument = report
                };
            }
        }

        public static byte[] BuildReport(string reportPath, JsonNode jsonNode)
        {
            var reportProcessor = new Telerik.Reporting.Processing.ReportProcessor();

            // set any deviceInfo settings if necessary
            var deviceInfo = new System.Collections.Hashtable();

            ReportSource reportSource = GetReportSource(reportPath, jsonNode);

            Telerik.Reporting.Processing.RenderingResult result = reportProcessor.RenderReport("PDF", reportSource, deviceInfo);

            if (!result.HasErrors)
            {
                return result.DocumentBytes;
            }
            else
            {
                throw new Exception(string.Join(", ", result.Errors.Select(ex => ex.Message)));
            }
        }

        public static byte[] BuildReport(string templatePath, JsonElement root)
        {
            JsonNode? jsonNode = JsonNode.Parse(root.GetRawText());
            if (jsonNode == null)
            {
                throw new ArgumentNullException(nameof(jsonNode), "Parsed JsonNode cannot be null.");
            }
            return BuildReport(templatePath, jsonNode);
        }
    }
}

1 Answer, 1 is accepted

Sort by
0
Petar
Telerik team
answered on 21 Mar 2025, 04:29 PM

Hello Don,

I believe I addressed your concern in the private thread 1682494. If you have any further questions about this matter, I recommend posting your messages there, as the response time is 24 hours. That being said, we try our best to answer questions from users in our Q&A forum as well, but please note that the response time is usually slower due to lower priority.

Nonetheless, I will post my answer to the question here as well, as it may be helpful for other users who come across this problem.

------------------------------------------------------------------------------------------

I suspect the report sources for the SubReport items are passed as relative paths, such as "SubFinalReportV1_PatientDemographics.trdp" or "./SubFinalReportV1_PatientDemographics.trdp". Is that correct?

Please note that there is a difference in how relative paths are handled when using UriReportSource versus InstanceReportSource. When using UriReportSource, you provide the exact path to the report, and all inner resources defined with relative paths, such as subreports, are resolved relative to the parent folder of the rendered report. If I understand your concern correctly, this is the behavior you are seeking.

In contrast, when you pass InstanceReportSource to the RenderReport method of the ReportProcessor, relative paths are resolved based on the application's base folder, which is what you are observing based on the error messages you provided.

To address the issue you are experiencing, there are several solutions you might consider:
  • Provide absolute paths for the subreports. You can configure this through the `ReportSource` property of the subreport, as shown in the screenshot above.
  • Modify the relative paths so they point to the correct folder. For example, you can use a path like `./Reports/SubFinalReportV1_PatientDemographics.trdp`.
  • Instead of using InstanceReportSource, pass a UriReportSource to the RenderReport method of the ReportProcessor. This allows relative paths to be resolved based on the parent folder of the rendered report file. Therefore, if your subreports are located in the same directory, there shouldn't be any issues. If you decide to go this way, you might consider packaging the modified report into a new TRDP file placed in the same directory as the other reports. Then, you can render that newly packaged report file by passing its Uri to a UriReportSource.

Regards,
Petar
Progress Telerik

Enjoyed our products? Share your experience on G2 and receive a $25 Amazon gift card for a limited time!

Don
Top achievements
Rank 1
commented on 21 Mar 2025, 06:14 PM

Thanks Petar, exactly what I needed. The report was originally unpackaged in order to get the datasource out of the report template and populate it with Json. Switching to a UriReportSource was simpler in that the json was passed through a parameter, which in the end is more straightforward and with the UriReportSource all the subreports are found. 

Here is the modified creation of the ReportSource

        public static ReportSource GetUriReportSource(string reportPath, JsonNode jsonNode)
        {
            // Create the UriReportSource and set the report path (relative to your reports location)
            var uriReportSource = new UriReportSource
            {
                Uri = reportPath
            };

            // Add a parameter to the report source with the JSON string
            uriReportSource.Parameters.Add("pJsonData", jsonNode.ToJsonString(new System.Text.Json.JsonSerializerOptions { WriteIndented = true }));

            return uriReportSource;
        }

 

 

Tags
SubReport
Asked by
Don
Top achievements
Rank 1
Answers by
Petar
Telerik team
Share this question
or