Hi everyone.
We have an extremely frustrating problem we are attempting to solve.
We have a .NET 7 Web Application using a Blazor Server hosting model for reporting. The application is containerized and runs as part of a service via AWS Fargate. We have a series of legacy reports that we have converted to '.trdp' format, several of these reports use a named connection string to interact with RDS (AWS SQL DB).
We are using the 'Blazor' reporting solution that is merely a wrapper over the HTML5 reporting. The assembly versions are as follows:
Telerik.Drawing.Skia, 17.2.23.1114 Telerik.Reporting, 17.2.23.1114 Telerik.Reporting.OpenXmlRendering, 17.2.23.1114 Telerik.Reporting.Services.AspNetCore, 17.2.23.1114 Telerik.ReportViewer.Blazor, 17.2.23.1114
As part of our build process - we inject a secrets file into the container definition with the credentials for accessing the db. This is modified during launch to include the correct environment db and db credentials:
if (ConnectionUtility.IsRunningInFargate())
{
// Create new copy of string in memory so we can modify it
var connectionString = connectionStrings[Constants.ReportingSqlConnectionKey];
var databaseUriForEnvironment = ConnectionUtility.GetDatabaseUriForEnvironment();
var databaseForEnvironment = ConnectionUtility.GetDatabaseForEnvironment();
// Replace placeholders with values
var protoConnectionString =
connectionString!
.Replace("{0}", databaseUriForEnvironment)
.Replace("{1}", databaseForEnvironment);
// Important! - This replaces the 'in-memory' connection string that reports use to interact with the primary db
connectionStrings[Constants.ReportingSqlConnectionKey] = protoConnectionString.TransformSecret(Constants.SettingClass.ConnectionString);
}
The connection string key isn't important here, but it is used to provide the connection key for each report.;
The Telerik services are injected:
builder.Services.TryAddSingleton<IReportServiceConfiguration>(sp => new ReportServiceConfiguration
{
ReportingEngineConfiguration = sp.GetService<IConfiguration>(),
HostAppId = "X.Reporting",
Storage = new FileStorage(),
ExceptionsVerbosity = "detailed",
ReportSourceResolver =
new CustomReportSourceResolverWithFallBack(
new TypeReportSourceResolver()
.AddFallbackResolver(
new UriReportSourceResolver(
Path.Combine(
GetReportsDir(sp))))),
});
The resolver is less important, but for the sake of completion:
using Telerik.Reporting;
using Telerik.Reporting.Services;
namespace X.Reporting.Services
{
public class CustomReportSourceResolverWithFallBack : IReportSourceResolver
{
private readonly IReportSourceResolver? _parentResolver;
public CustomReportSourceResolverWithFallBack(IReportSourceResolver? parentResolver)
{
_parentResolver = parentResolver;
}
public ReportSource Resolve(string report, OperationOrigin operationOrigin, IDictionary<string, object> currentParameterValues)
{
var reportDocument = ResolveCustomReportSource(report, operationOrigin, currentParameterValues);
if (null == reportDocument && null != _parentResolver)
{
reportDocument = _parentResolver.Resolve(report, operationOrigin, currentParameterValues);
}
return reportDocument;
}
private ReportSource ResolveCustomReportSource(string reportId, OperationOrigin operationOrigin, IDictionary<string, object> currentParameterValues)
{
var reportBook = new ReportBook();
var splitString = reportId.Split(',').ToList();
foreach (var report in splitString)
{
var uriReportSource = new UriReportSource
{
Uri = $"Reports/{report}.trdp"
};
reportBook.ReportSources.Add(uriReportSource);
if (operationOrigin == OperationOrigin.ResolveReportParameters)
{
reportBook.ReportSources.Add(GetReportParameters(report, currentParameterValues));
}
}
return new InstanceReportSource { ReportDocument = reportBook };
}
private ReportSource GetReportParameters(string reportId, IDictionary<string, object> currentParameterValues)
{
UriReportSource report = new UriReportSource();
foreach (var parameterValue in currentParameterValues)
{
if (parameterValue.Value is not null and not (string)"standardReport")
{
var par = new Parameter
{
Name = parameterValue.Key,
Value = parameterValue.Value.ToString()
};
report.Parameters.Add(par);
report.Uri = $"Reports/{reportId}.trdp";
}
}
return report;
}
}
}
90 % of the time, we can render reports without issue. However, there are times where any report that uses a SQL connection seems to be unable to reach our primary database. EF Core (which interacts with the same DB prior to and after rendering reports) seems to never have this issue - even when Telerik does. Both share the exact same connection string. Rendering a report with an included SQL query returns something like the following:
On occasion, this issue seems to resolve itself after ~5 minutes. Most of time, we need to kill the container instance and restart it a number of times before reports render without issue. I'm confounded why this happens - it 'feels' like the underlying SQL connection is reused.
Any help is appreciated - this has been a critical issue to our clients, we can't keep using this reporting solution without a fix.
Hi Everyone,
I've recently upgrade telerik reporting to the last version. I'm currently using the report viewer in a .net core application on linux. Since the last version the print option and the pdf export doesn't work anymore.
On the front end i'm getting
telerik reporting The header contains invalid values at index 0: '<null>'
and on the server server side I'm getting an exception with
telerik.Reporting.Pdf.Fonts.TrueType.FontDataProvider
I've set the appsettings to use the GDI and still have the system.drawing.common set at 6.0 for now. I never had any issues prior to this update with the same settings. Anyone had this issue before? All other export works perfectly fine, only the pdf and print options have issues.
Thank you very much,
Guillaume
Hello.
Currently I am designing a report on which I have date and datetime data types.
I have prepared the data-base table with data that goes into the report (attachment data-model.png)
I prepared report template in telerik web report designer (attachment report_template.png)
I set format according to Standard DateTime Format Strings
Field with date data has format {0:d}
On preview (at Web Report Designer) the date seems to be ok (attachment preview.png)
Unfortunately, after exporting the report to excel (xlsx), the date type is not a date in excel (attachment invalid_format.png)
My appsetting.json file contains
"telerikReporting": {
"extensions": [
{
"name": "XLSX",
"parameters": [
{
"name": "UseExtendedFormatting",
"value": "False"
}
]
}
]
}
What should I have to set/do in order to have date format in excel for cells that contain date and date-time data?
I would like to achieve result like below: for cell that contain date data in report I need date format in excel
I would like to emphasize that Standard Numeric Format Strings work:
Environment:
regards
Dear supporting team,
First of all, I apologize for the typo in the title. I can't fix it
I used Telerik reporting to design the report.
But I was facing a problem. I can not or don't know how to get the session value or cookie value in the ASP.NET Core Web App project.
The way I do it is:
<script type="text/javascript">
$(document).ready(function () {
var au = document.cookie.split('=');
var uname = au[1];
var urlParams = new URLSearchParams(window.location.search);
var rp = urlParams.get('r');
$("#reportViewer1")
.telerik_ReportViewer({
serviceUrl: "/api/reports",
reportSource: {
report: "INV_ADJUSTMENT_DETAIL.trdx",
parameters: { user_name: uname, report: rp }
},
viewMode: telerikReportViewer.ViewModes.INTERACTIVE,
scaleMode: telerikReportViewer.ScaleModes.SPECIFIC,
scale: 1.0,
enableAccessibility: false,
sendEmail: { enabled: false },
ready: function () {
},
});
});
</script>
And in the Program.cs
.....
builder.Services.TryAddSingleton<IReportServiceConfiguration>(sp => new ReportServiceConfiguration
{
ReportingEngineConfiguration = sp.GetService<IConfiguration>(),
HostAppId = "Html5ReportViewerDemo",
Storage = new FileStorage(),
ReportSourceResolver = new CustomReportSourceResolver()
});
builder.Services.AddSingleton<IHttpContextAccessor, HttpContextAccessor>();
builder.Services.AddHttpContextAccessor();
builder.Services.AddDistributedMemoryCache();
builder.Services.AddSession(session =>
{
session.IdleTimeout = TimeSpan.FromMinutes(60);
session.Cookie.HttpOnly = true;
session.Cookie.IsEssential = true;
});
.....
In the report designer, how can I use the value in reportSource -> parameters?
Is there a possible solution for this? please help advise.
Visual Studio version: Microsoft Visual Studio Professional 2022
Framework: .Net 6.0
Telerik packages:
Many thanks,
Dinh Phong
Hello,
How do we change the datasource of Telerik reporting dynamically using Business Object ?
I'm playing with Sample CSharp.Net6.HtmlIntegration from R1 2023 Telerik Reporting
Here's my code :
(Reporting.cshtml)
@{
string report = ViewBag.Report + ".trdp";
}
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title>Telerik HTML5 Report Viewer Demo</title>
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1" />
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<link href="https://kendo.cdn.telerik.com/2022.3.913/styles/kendo.common.min.css" rel="stylesheet" id="common-css" />
<link href="https://kendo.cdn.telerik.com/2022.3.913/styles/kendo.blueopal.min.css" rel="stylesheet" id="skin-css" />
<script src="/Scripts/themeSwitcher.js"></script>
<script src="/api/reports/resources/js/telerikReportViewer"></script>
<style>
body {
font-family: Verdana, Arial, sans-serif;
margin: 5px;
}
#reportViewer1 {
position: absolute;
left: 5px;
right: 5px;
top: 40px;
bottom: 5px;
overflow: hidden;
clear: both;
}
#theme-switcher {
float: right;
width: 12em;
height: 30px;
}
</style>
</head>
<body>
<select id="theme-switcher"></select>
<div id="reportViewer1">
loading...
</div>
<script type="text/javascript">
$(document).ready(function () {
//Theme switcher
themeSwitcher(
'#theme-switcher',
'#common-css',
'#skin-css');
$("#reportViewer1")
.telerik_ReportViewer({
serviceUrl: "api/reports/",
reportSource: {
report: "@report",
},
viewMode: telerikReportViewer.ViewModes.INTERACTIVE,
scaleMode: telerikReportViewer.ScaleModes.SPECIFIC,
scale: 1.0,
enableAccessibility: false,
//If set to true shows the Send Mail Message toolbar button
sendEmail: { enabled: true }
});
});
</script>
</body>
</html>
(ReportingController.cs)
using Microsoft.AspNetCore.Mvc;
namespace CSharp.Net6.Html5IntegrationDemo.Controllers
{
public class ReportingController : Controller
{
[Route("reporting")]
public IActionResult Index(string report)
{
ViewBag.Report = report;
return View("Reporting");
}
}
}
My report viewer was working without issue for some time until caching with DistributedSqlServerCache was implemented. It is configured as follows.
services.TryAddSingleton<IReportServiceConfiguration>(configuration =>
new ReportServiceConfiguration {
HostAppId = "Reports",
ReportingEngineConfiguration = new ConfigurationBuilder().AddJsonFile(Path.Combine(configuration.GetService<IWebHostEnvironment>().ContentRootPath, "appsettings.json"), true).Build(),
ReportSourceResolver = new UriReportSourceResolver(Path.Combine(configuration.GetService<IWebHostEnvironment>().ContentRootPath, "App_Data")).AddFallbackResolver(new TypeReportSourceResolver()),
Storage = new MsSqlServerStorage("connection-string")
}
);
public class ReportsController : ReportsControllerBase {
public ReportsController(IReportServiceConfiguration reportServiceConfiguration) : base(reportServiceConfiguration) {
reportServiceConfiguration.Storage.AcquireLock(string.Format("Lock-{0}", new Random().Next()));
}
}
Note that the AcquireLock() method mentioned above was added in response to this comment from Telerik:
The interface also exposes a method called AcquireLock which is used from the service to enforce serialized access to all stored resources from each thread of the application and between the instances of the application in case of multi-instance environment (i.e., Web Farm)
Which I suspect may apply here, but unfortunately I can only hazard guess in light of its appalling lack of documentation.
A typical error message reported by the viewer is:
Error creating report document (Report = 'XXXXX, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null'; Format = 'HTML5'). An error has occurred. Object reference not set to an instance of an object.
function registerDocumentAsync(format, deviceInfo, useCache, baseDocumentId, actionId) {
throwIfNotInitialized();
throwIfNoReportInstance();
return client.createReportDocument(clientId, reportInstanceId, format, deviceInfo, useCache, baseDocumentId, actionId).catch(function(xhrErrorData) {
handleRequestError(xhrErrorData, utils.stringFormat(sr.errorCreatingReportDocument, [ utils.escapeHtml(report), utils.escapeHtml(format) ]));
});
}
to this:
function registerDocumentAsync(format, deviceInfo, useCache, baseDocumentId, actionId) {
throwIfNotInitialized();
throwIfNoReportInstance();
return client.createReportDocument(clientId, reportInstanceId, format, deviceInfo, useCache, baseDocumentId, actionId).catch(function () {
console.log("Failed to create report document. A retry has been attempted.");
return client.createReportDocument(clientId, reportInstanceId, format, deviceInfo, useCache, baseDocumentId, actionId).catch(function (xhrErrorData) {
handleRequestError(xhrErrorData, utils.stringFormat(sr.errorCreatingReportDocument, [utils.escapeHtml(report), utils.escapeHtml(format)]));
});
});
}
We followed your instructions to make the reports (https://www.youtube.com/watch?v=UF1mL6vzJDs&t=738s). But I have 1 question, how do we decentralize these reports?
For example:
We have 2 reports on 2 html pages, report1.html and report2.html
We have 2 users, user_a and user_b
user_a can only access report1.html
and user_b can only access report2.html
----------------------------------------------------------------------
Microsoft Visual Studio Professional 2022 (64-bit) Framework: .NET 6 Telerik Reporting trial version 17.0.23.118 Telerik HTML5 Report Viewer Page R1 2023
----------------------------------------------------------------------
Hi,
I understand there are two view modes: Interactive and Print Preview.
My question: How do I load all pages on print preview mode?
What I am getting at the moment is the ReportViewer (on Print Preview Mode) loads 2 first pages, and waits for the user to scroll down the ReportViewer before loading the next page (page 3, 4 and so on).
Thanks,
Angga