Action NavigateToReport does not work after updating the Connection String dynamically in a Custom Report Resolver
Environment
| Product | Progress® Telerik® Reporting |
Description
Sometimes it is necessary to change the connection string dynamically, in the code. The approach described in Changing the connection string dynamically according to runtime data KB article is suitable for Desktop Viewers.
It can be applied also for the Html5 Web Viewers with some modifications. The connection string should be changed in the Resolve() method of the Custom Report Resolver.
When there is a NavigateToReport Action set for any report item, the action will not work after updating the connection string.
Solution
The above KB article drills through the entire report to modify the connection string of all its Items, Parameters and Actions. The code from the KB searches for NavigateToReport Actions, and replaces recursively the connection string also in Action ReportSources. That is where the problem occurs. You should remove the corresponding code that drills through the Actions, as it is excessive in the case of Html5 Report Viewer / REST Service. The REST Service will automatically resolve the ReportSource of the NavigateToReport Action using the Custom Report Resolver, hence its connection string will be automatically modified and it is not necessary to drill through actions in the main report.
The following code is appropriate for applications using Telerik Reporting REST Service:
class ReportConnectionStringManager
{
readonly string connectionString;
public ReportConnectionStringManager(string connectionString)
{
this.connectionString = connectionString;
}
public ReportSource UpdateReportSource(ReportSource sourceReportSource)
{
if (sourceReportSource is UriReportSource)
{
var uriReportSource = (UriReportSource)sourceReportSource;
// unpackage TRDP report
var reportInstance = UnpackageReport(uriReportSource);
// or deserialize TRDX report(legacy format)
// var reportInstance = DeserializeReport(uriReportSource);
ValidateReportSource(uriReportSource.Uri);
this.SetConnectionString(reportInstance);
return CreateInstanceReportSource(reportInstance, uriReportSource);
}
if (sourceReportSource is XmlReportSource)
{
var xml = (XmlReportSource)sourceReportSource;
ValidateReportSource(xml.Xml);
var reportInstance = this.DeserializeReport(xml);
this.SetConnectionString(reportInstance);
return CreateInstanceReportSource(reportInstance, xml);
}
if (sourceReportSource is InstanceReportSource)
{
var instanceReportSource = (InstanceReportSource)sourceReportSource;
this.SetConnectionString((ReportItemBase)instanceReportSource.ReportDocument);
return instanceReportSource;
}
if (sourceReportSource is TypeReportSource)
{
var typeReportSource = (TypeReportSource)sourceReportSource;
var typeName = typeReportSource.TypeName;
ValidateReportSource(typeName);
var reportType = Type.GetType(typeName);
var reportInstance = (Report)Activator.CreateInstance(reportType);
this.SetConnectionString((ReportItemBase)reportInstance);
return CreateInstanceReportSource(reportInstance, typeReportSource);
}
throw new NotImplementedException("Handler for the used ReportSource type is not implemented.");
}
ReportSource CreateInstanceReportSource(IReportDocument report, ReportSource originalReportSource)
{
var instanceReportSource = new InstanceReportSource { ReportDocument = report };
instanceReportSource.Parameters.AddRange(originalReportSource.Parameters);
return instanceReportSource;
}
void ValidateReportSource(string value)
{
if (value.Trim().StartsWith("="))
{
throw new InvalidOperationException("Expressions for ReportSource are not supported when changing the connection string dynamically");
}
}
Report UnpackageReport(UriReportSource uriReportSource)
{
var reportPackager = new ReportPackager();
using (var sourceStream = System.IO.File.OpenRead(uriReportSource.Uri))
{
var report = (Report)reportPackager.UnpackageDocument(sourceStream);
return report;
}
}
Report DeserializeReport(UriReportSource uriReportSource)
{
var settings = new System.Xml.XmlReaderSettings();
settings.IgnoreWhitespace = true;
using (var xmlReader = System.Xml.XmlReader.Create(uriReportSource.Uri, settings))
{
var xmlSerializer = new Telerik.Reporting.XmlSerialization.ReportXmlSerializer();
var report = (Telerik.Reporting.Report)xmlSerializer.Deserialize(xmlReader);
return report;
}
}
Report DeserializeReport(XmlReportSource xmlReportSource)
{
var settings = new System.Xml.XmlReaderSettings();
settings.IgnoreWhitespace = true;
var textReader = new System.IO.StringReader(xmlReportSource.Xml);
using (var xmlReader = System.Xml.XmlReader.Create(textReader, settings))
{
var xmlSerializer = new Telerik.Reporting.XmlSerialization.ReportXmlSerializer();
var report = (Telerik.Reporting.Report)xmlSerializer.Deserialize(xmlReader);
return report;
}
}
void SetConnectionString(ReportItemBase reportItemBase)
{
if (reportItemBase.Items.Count < 1)
return;
if (reportItemBase is Report)
{
var report = (Report)reportItemBase;
if (report.DataSource is SqlDataSource)
{
var sqlDataSource = (SqlDataSource)report.DataSource;
sqlDataSource.ConnectionString = connectionString;
}
foreach (var parameter in report.ReportParameters)
{
if (parameter.AvailableValues.DataSource is SqlDataSource)
{
var sqlDataSource = (SqlDataSource)parameter.AvailableValues.DataSource;
sqlDataSource.ConnectionString = connectionString;
}
}
}
foreach (var item in reportItemBase.Items)
{
//recursively set the connection string to the items from the Items collection
SetConnectionString(item);
if (item is SubReport)
{
var subReport = (SubReport)item;
subReport.ReportSource = this.UpdateReportSource(subReport.ReportSource);
continue;
}
//Covers all data items(Crosstab, Table, List, Graph, Map and Chart)
if (item is DataItem)
{
var dataItem = (DataItem)item;
if (dataItem.DataSource is SqlDataSource)
{
var sqlDataSource = (SqlDataSource)dataItem.DataSource;
sqlDataSource.ConnectionString = connectionString;
continue;
}
}
}
}
}Notes
When navigating to a Standalone designer report (.trdp, .trdx, .trbp) the paths to the reports will be resolved with respect to the application, not with respect to the main report. This may cause broken NavigateToReport Actions when the report is not in the main folder of the application. To resolve the issue it will be necessary to replace the base path from the UriReportSource.Uri with the actual one (path to the application main folder).
Connection string can be modified run time without extra code, based on Report Parameter: Change Connection String dynamically through a report parameter.