Hosting the Telerik Reporting REST Service in ASP.NET Core in .NET 6, .NET 7, and .NET 8 with Top-Level Statements
This article guides you how to host a Reports Web Service in order to expose the Reports Generation Engine to an ASP.NET Core in .NET 6 and higher Web Application with Top-Level Statements implementation. Check the Microsoft Tutorial: Explore ideas using top-level statements to build code as you learn for general details on the approach.
The guide is separated into sections for readability reasons. Along with the steps, it elaborates on the concepts and theory behind each step.
Prerequisites
- Visual Studio 2022, version 17+
- NET 6 SDK or higher
Using the REST Service Project Template
In Visual Studio open the Add New Project dialog and select Telerik Reporting REST Service project template. After clicking Create
a menu pops up that allows you to configure the following properties of the REST Service: target framework, service clients (report viewer and report designer), Cross-Origin Resource Sharing, Host Application ID, and Application URL.
Set the Target Framework to .NET 6, or correspondingly to .NET 7, or .NET 8.
Once you have configured the rest of the options to your liking, click Finish
and a new project, containing all the necessary files and packages to host the Telerik Reporting REST service instance, will be added to your solution.
Manually configuring the Telerik.Reporting REST Service
Creating a Sample ASP.NET Core in .NET 6+ Project
First, you need to create a new ASP.NET Core project:
- Open Visual Studio 2022.
- From the File menu, select New > Project.
- In the Create a new project dialog select ASP.NET Core Web App project template and click Next.
- In the Configure your new project dialog choose a name and location for the project and click Next.
- In the Additional information dialog select from the drop down .NET 6.0 (Long-term support), or correspondingly .NET 7, or .NET 8. If you configure the project for HTTPS make sure to have a proper certificate assigned. Click on Create.
Add Report Definitions
In this tutorial, the resulting service will use the sample report definitions deployed with the Telerik Reporting product installer:
- Find the sample reports in {Telerik Reporting installation path}\Report Designer\Examples.
- Add a new folder to your solution called
Reports
and copy all sample reports into it. - Later in the tutorial we will make sure that the ReportsController is able to resolve the definitions for the requested reports from this project folder.
It is recommended to use declarative definitions (TRDP/TRDX/TRBP) authored using the Standalone Report Designer or the Web Report Designer in order to take advantage of their design-time tooling because the VS integrated report designer tooling is still not available in .NET 6+ projects.
Add the required dependencies
This guide applies the recommended NuGet package references approach to add the dependencies:
- Reference the Telerik.Reporting.Services.AspNetCore (or Telerik.Reporting.Services.AspNetCore.Trial) package.
- Optionally, to enable the Office OpenXML document formats (XLSX, DOCX and PPTX) as export options, reference the Telerik.Reporting.OpenXmlRendering (or Telerik.Reporting.OpenXmlRendering.Trial) NuGet package.
The recommended way of adding the necessary dependencies is to use the Progress Telerik proprietary NuGet feed and reference the dependencies as NuGet packages. This would also add the indirect dependencies to your project bringing easier dependency management. Alternatively, the assemblies are available in the
\Bin\net6.0\
and\Bin\netstandard2.0\
folders of Telerik Reporting installation directory. However, this would require to manually add all indirect dependencies listed in .NET Support - Requirements section and also the following dependency package: Microsoft.AspNetCore.Mvc.NewtonsoftJson version 5.0.0 and DocumentFormat.OpenXML version 2.7.2.0 or above. Note that you need the last reference only to enable the Office OpenXML document formats. The Reporting engine relies on the GDI+ API which is available on the Windows OS. On Linux and macOS we use library called libgdiplus instead. The GDI+ API is required for measuring, laying out, rendering the text glyphs and images.
Setup the Program.cs file as a starting point of your Reporting REST Service project with Top-Level Statements
Modify the Program.cs
file in the project to enable the Reports Service functionality.
-
Make sure the application is configured for WebAPI controllers and call the
AddNewtonsoftJson
on the IMvcBuilder object to place the NewtonsoftJson serialization:builder.Services.AddControllers().AddNewtonsoftJson();
-
Add the dedicated configuration object needed from the Reports Service in the dependency container. Note how the report source resolver will target the Reports folder we created earlier.
// Configure dependencies for ReportsController. builder.Services.TryAddSingleton<IReportServiceConfiguration>(sp => new ReportServiceConfiguration { // The default ReportingEngineConfiguration will be initialized from appsettings.json or appsettings.{EnvironmentName}.json: ReportingEngineConfiguration = sp.GetService<IConfiguration>(), // In case the ReportingEngineConfiguration needs to be loaded from a specific configuration file, use the approach below: //ReportingEngineConfiguration = ResolveSpecificReportingConfiguration(sp.GetService<IWebHostEnvironment>()), HostAppId = "ReportingNet6", Storage = new FileStorage(), ReportSourceResolver = new UriReportSourceResolver(System.IO.Path.Combine(sp.GetService<IWebHostEnvironment>().ContentRootPath, "Reports")) });
-
Make sure the endpoints are configured for API controllers by adding the following line in the lambda expression argument after the UseRouting(); call:
app.UseEndpoints(endpoints => { endpoints.MapControllers(); //... });
Add Configuration Settings to the Program.cs file (Optional)
The report generation engine can retrieve SQL Connection Strings and specific Report Generation Engine Settings that provide flexibility of the deployed application. It utilizes the IConfiguration interface for this purpose.
The .NET applications use a key-value JSON-based file named by default appSettings.json
. The default ReportingEngineConfiguration:
ReportingEngineConfiguration = sp.GetService<IConfiguration>();
will be initialized from appSettings.json
or appsettings.{EnvironmentName}.json
.
To activate JSON file configuration with a different name, for example, reportingAppSettings.json
, call the AddJsonFile extension method on an instance of ConfigurationBuilder.
In this guide we will create a helper method loading the json-formatted setting:
static IConfiguration ResolveSpecificReportingConfiguration(IWebHostEnvironment environment)
{
// If a specific configuration needs to be passed to the reporting engine, add it through a new IConfiguration instance.
var reportingConfigFileName = System.IO.Path.Combine(environment.ContentRootPath, "reportingAppSettings.json");
return new ConfigurationBuilder()
.AddJsonFile(reportingConfigFileName, true)
.Build();
}
Finally, all configurations should be placed in the JSON configuraion file (add one in the project root if such does not exist). For example, ConnectionStrings setting should be configured in JSON-based format like this:
{
//...
"ConnectionStrings": {
"Telerik.Reporting.Examples.CSharp.Properties.Settings.TelerikConnectionString": "Data Source=.\\SQLEXPRESS;Initial Catalog=AdventureWorks;Integrated Security=true"
}
}
The above type of connection string lacks information about the data provider and will use System.Data.SqlClient as provider invariant name. When it's necessary to specify a different data provider, the following notation is also supported:
{
//...
"ConnectionStrings": {
"Telerik.Reporting.Examples.CSharp.Properties.Settings.TelerikConnectionString": {
"connectionString": "Data Source=.\\SQLEXPRESS;Initial Catalog=AdventureWorks;Integrated Security=true",
"providerName": "System.Data.SqlClient"
}
}
}
The two types of connection string notations specified above can coexist in a single ConnectionStrings section.
The last supported type of ConnectionStrings configuration uses an array to provide information about each connection string:
{
//...
"ConnectionStrings": [
{
"name": "Telerik.Reporting.Examples.CSharp.Properties.Settings.TelerikConnectionString",
"connectionString": "Data Source=.\\SQLEXPRESS;Initial Catalog=AdventureWorks;Integrated Security=true",
"providerName": "System.Data.SqlClient"
}
]
}
Setting up the REST service
- Create folder
Controllers
. Right-click on the project name and select Add > New folder. Name itControllers
. - Implement a Reports controller. Right-click on the
Controllers
folder and add a new item: Add > New item > API Controller - Empty item. Name itReportsController
. This will be our Telerik Reporting REST service in the project. -
Inherit the ReportsControllerBase type and inject the configuration settings in the constructor. This is how a basic implementation of the controller should look like:
namespace TopLevelStatements.Controllers { using System.Net; using System.Net.Mail; using Microsoft.AspNetCore.Mvc; using Telerik.Reporting.Services; using Telerik.Reporting.Services.AspNetCore; [Route("api/[controller]")] [ApiController] public class ReportsController : ReportsControllerBase { public ReportsController(IReportServiceConfiguration reportServiceConfiguration) : base(reportServiceConfiguration) { } protected override HttpStatusCode SendMailMessage(MailMessage mailMessage) { throw new System.NotImplementedException("This method should be implemented in order to send mail messages"); // using (var smtpClient = new SmtpClient("smtp01.mycompany.com", 25)) // { // smtpClient.DeliveryMethod = SmtpDeliveryMethod.Network; // smtpClient.EnableSsl = false; // smtpClient.Send(mailMessage); // } // return HttpStatusCode.OK; } } }
Test the service implementation
To ensure that the service operates, run the application and navigate to either of the General REST Service API URLs {applicationRoot}/api/reports/formats
or {applicationRoot}/api/reports/version
. The first should return a JSON representing the supported rendering extensions, and the second - the version of the Reporting REST Service.
Enable Cross-Origin Resource Sharing (CORS) (Optional)
You may need to enable Cross-Origin Resource Sharing (CORS), for example, if you use the REST Service from clients hosted in different domains.
Add the following service to the Program.cs file to add a new CORS policy for the REST Service:
builder.Services.AddCors(corsOption => corsOption.AddPolicy(
"ReportingRestPolicy",
corsBuilder =>
{
corsBuilder.AllowAnyOrigin()
.AllowAnyMethod()
.AllowAnyHeader();
}
));
Activate the above policy for the application by adding the code below in the application configuration part of the Program.cs
file:
app.UseCors("ReportingRestPolicy");
Demo project
A full example can be found in the installation folder of Telerik Reporting:
C:\Program Files (x86)\Progress\Telerik Reporting 2024 Q3\Examples\CSharp\.NET 6\ReportingRestServiceCorsDemo\CSharp.Net6.ReportingRestServiceCorsDemo