How to Create an RDL Report in .NET C# Code

MESCIUS inc.
MESCIUS inc.
Published in
8 min readJul 17, 2024

What You Will Need
• Visual Studio 2017–2022
• ActiveReports.NET

Controls Referenced
Page and RDLX reports — Table

Tutorial Concept
RDL Reports in C# — The tutorial guides you through the process of setting up your environment, writing the necessary code, and customizing your report for specific data outputs.

There are instances where it becomes necessary to programmatically generate an RDL report in C# code, manage data binding conditionally at runtime, or modify the layout of a report based on user input. This blog provides a comprehensive guide on the procedures required to create an RDL report from the ground up, using code exclusively.

To illustrate this process, we will develop a project that displays a list of countries on the left side of the page. Upon selecting a country, a report will be generated that lists all customers residing in that country, along with their contact information (refer to the image below).

This blog will show you how to:

  • Set up the project
  • Create an RDL report C#
  • Create a table using C#
  • Create a parameter
  • Manage data binding
  • Pass the report to the JSViewer using CustomStore

Set Up the Project

First, we will create a new ActiveReports 18 ASP.NET Core Application.

This project template is integrated into Visual Studio when you install ActiveReports. The template will install all the NuGet packages and resources required to render a report in the JSViewer, eliminating the need for manual installation.

Open the index.html file in the wwwroot:

Use a Listbox to display our country list by modifying the code in the body tag as follows:

    <div style="width: 100%; overflow-x: hidden">

<div style="float:left; width: 125pt" class="main-nav navbar">

<div id='list-heading'>Select Country</div>

<ul id="countriesList" class="nav navbar-nav"></ul>

</div>

<div style="float:right;width:calc(100% - 125pt)" id="viewerContainer">

</div>

</div>

Then, change the onload event of the body to populate the countriesList.

<body onload="populateList()">

The code below shows how to fetch the “countries” field from a JSON service, create a distinct and sorted list, and populate the countriesList element.

function populateList() {
let countriesList = document.getElementById("countriesList");
let oReq = new XMLHttpRequest();
oReq.onload = function () {
var lookup = {};
var countriesObj = [];
fetch('https://demodata.grapecity.com/northwind/api/v1/Customers')
.then(res => res.json())
.then((out) => {
for (var item, i = 0; item = out[i++];) {
var country = item.country;
if (!(country in lookup)) {
lookup[country] = 1;
countriesObj.push(country);
}
}
countriesObj.sort();
for (let i = 0; i < countriesObj.length; i++) {
const countryName = countriesObj[i];
const countries = document.createElement('li');
countries.className = 'countriesList_item';
const countryItem = document.createElement('span');
countryItem.innerText = countryName;
countries.appendChild(countryItem);
countriesList.appendChild(countries);

countries.addEventListener('click', function () {
loadViewer(countryName);
});
}
})
.catch(err => { throw err });
}
oReq.open("get", "reports", false);
oReq.send();
}

At this point, we’ve created the countriesList element, populated it, and added an event listener to pass the selected country from this list to the loadViewer() function. The loadViewer function takes the user input, a parameter, and passes it to the report to display filtered data:

let viewer=null;
function loadViewer(country) {
if (viewer == null) {
viewer = GrapeCity.ActiveReports.JSViewer.create({
element: '#viewerContainer',
reportID: "MyReport",
reportParameters: [{ name: 'selectedCountry', values: [country] }]
});
}
else { viewer.openReport("MyReport", [{name: 'selectedCountry', values:[country]}])}
}

Create an RDL Report

For the RDL report, let’s create a custom class in the Reports folder. We’ll call it ReportDefinition.cs. Let’s start by creating a public instance of an RDL report C#:

static class ReportDefinition {
PageReport CreateReport(){
var report = new PageReport();

//Cofigure report here as descibed below

return report;
}
}

Create the layout of the report’s page in the constructor:

 rdlReport.Report.PaperOrientation = GrapeCity.ActiveReports.PageReportModel.PaperOrientation.Landscape;
rdlReport.Report.PageHeight = "8in";
rdlReport.Report.PageWidth = "11in";

//Page Header
var headers = new GrapeCity.ActiveReports.PageReportModel.PageHeaderFooter();
rdlReport.Report.PageHeader = headers;
headers.Height = ".5in";
headers.PrintOnFirstPage = true;
headers.PrintOnLastPage = true;

//Page Footer
var footer = new GrapeCity.ActiveReports.PageReportModel.PageHeaderFooter();
rdlReport.Report.PageFooter = footer;
footer.Height = ".5in";
footer.PrintOnFirstPage = true;
footer.PrintOnLastPage = true;

Next, add a report title at the very top of the page and page numbers in the page footer:

var reportTitle = new GrapeCity.ActiveReports.PageReportModel.TextBox()
{
Name = "ReportTitle",
Value = "=\"List of Customers in \" & Parameters!selectedCountry.Value",
Height = "0.5in",
Width = "5in",
Top = "0in",
Left = "0.5in",
Style = { TextAlign = "Left", FontSize = "18pt", FontWeight = "Bold" }
};

var pageNumber = new GrapeCity.ActiveReports.PageReportModel.TextBox();
pageNumber.Name = "pNumber";
pageNumber.Height = ".5cm";
pageNumber.Width = "1cm";
pageNumber.Left = "25cm";
pageNumber.Top = "0cm";
pageNumber.Value = "=Globals!PageNumber";
footer.ReportItems.Add(pageNumber);

Add every control we need in the report to the report definition. In this case, add the “reportTitle” textbox:

rdlReport.Report.Body.ReportItems.Add(reportTitle);

Create a Table in Code

The table will display our list of customers and their contacts in the specified country. Let’s create an instance of a table object using the code below:

var customersTable = new GrapeCity.ActiveReports.PageReportModel.Table()
{
Name = "CustomersTable",
Top = "0.75in",
Left = "0.5in",
DataSetName = "MyDataSet"
};

The table will need five columns (Company Name, Contact Name, Address, City, and Phone) and three rows (header, details, and footer). We will create a cell for each row and use it five times to represent the columns.

Let’s start by creating a customerHeader cell that will represent a cell in the table header:

//Creating table header
customersTable.Header = new GrapeCity.ActiveReports.PageReportModel.Header();
customersTable.Header.TableRows.Add(new GrapeCity.ActiveReports.PageReportModel.TableRow() { Height = ".4in" });
var customerHeader = customersTable.Header.TableRows[0].TableCells;

Then, format and style the customerHeader cell for each of the five columns and add it to the table:

//First cell in the table header
customerHeader.Add(new GrapeCity.ActiveReports.PageReportModel.TableCell());
customerHeader[0].ReportItems.Add(new GrapeCity.ActiveReports.PageReportModel.TextBox()
{
Name = "CompanyNameHeader",
Value = "Company Name",
Style = { BorderStyle = { Bottom = "Solid" },
VerticalAlign = "Middle",
PaddingLeft="3pt",
TextAlign = "Left",
BackgroundColor = "WhiteSmoke",
FontWeight = "Bold" }
});
customersTable.TableColumns.Add(new GrapeCity.ActiveReports.PageReportModel.TableColumn() { Width = "2.35in" });

Repeat this formatting for the rest of the four columns while changing the Name, Value, and Width properties accordingly.

Next, add a details row to the table. You only need one detail row, which will repeat as many times as there are records. Creating a details row follows the same procedure as creating the header row. But first, create the customerDetails cell that will represent a cell in the table details row:

//Detail Row
customersTable.Details.TableRows.Clear();
customersTable.Details.TableRows.Add(new GrapeCity.ActiveReports.PageReportModel.TableRow() { Height = ".3in" });
var customerDetails = customersTable.Details.TableRows[0].TableCells;

Now, it’s time to style the customerDetails cell for each column and add it to the details row:

//First cell in the Details row
customerDetails.Add(new GrapeCity.ActiveReports.PageReportModel.TableCell());
customerDetails[0].ReportItems.Add(new GrapeCity.ActiveReports.PageReportModel.TextBox()
{
Name = "CompanyNameBox",
Value = "=Fields!CompanyName.Value",
Width = "2.35in",
Style = { BorderColor = { Bottom = "WhiteSmoke" }, BorderStyle = { Bottom = "Solid" }, TextAlign = "Left", PaddingLeft="3pt", VerticalAlign="Middle"}
});

Again, repeat the same formatting for each of the remaining four columns while changing the Name, Value, and Width properties accordingly.

Similarly, create the table footer and add an expression to calculate the number of customers shown.

//Table footer
customersTable.Footer = new GrapeCity.ActiveReports.PageReportModel.Footer();
customersTable.Footer.TableRows.Add(new GrapeCity.ActiveReports.PageReportModel.TableRow() { Height = ".5in" });
var customerFooter = customersTable.Footer.TableRows[0].TableCells;

//First cell in the footer
customerFooter.Add(new GrapeCity.ActiveReports.PageReportModel.TableCell());
customerFooter[0].ReportItems.Add(new GrapeCity.ActiveReports.PageReportModel.TextBox()
{
Name = "CompanyNameFooter",
Value = "=\"Total Customer Count: \" & CountRows()",
Style = {
VerticalAlign ="Middle",
PaddingLeft="3pt",
TextAlign = "Left",
FontWeight = "Bold" }
});
customersTable.TableColumns.Add(new GrapeCity.ActiveReports.PageReportModel.TableColumn() { Width = "2.35in" });

With the customersTable now complete, add it to the report definition.

rdlReport.Report.Body.ReportItems.Add(customersTable);

Create a Parameter

When the user selects a country from the list box to the left of our page, that selection is passed to the report via a report parameter. In the next section, we’ll use this parameter to filter the data set.

You can either create this parameter in such a way as to prompt the user for input before rendering the report or hide the prompt altogether. By hiding the parameter, the user is not asked to enter a parameter value. In our case, since the user is already making a selection on our web page, we should create this as a hidden parameter outside of the viewer component.

//Create a hidden parameter
var selectedCountry = new GrapeCity.ActiveReports.PageReportModel.ReportParameter()
{
Name = "selectedCountry",
Prompt = "Select a country",
Hidden = true
};

//Add the parameter to the report
rdlReport.Report.ReportParameters.Add(selectedCountry);

Manage Data Binding

To manage the data binding, add a data source and a data set to the report in the ReportDefinition constructor as follows:

rdlReport.Report.DataSources.Add(myDataSource());
rdlReport.Report.DataSets.Add(myDataSet());

Then, use the myDataSource() method to connect to a JSON data source.

private GrapeCity.ActiveReports.PageReportModel.DataSource myDataSource()
{
GrapeCity.ActiveReports.PageReportModel.DataSource myDS = new GrapeCity.ActiveReports.PageReportModel.DataSource();
myDS.Name = "MyDataSource";
myDS.ConnectionProperties.DataProvider = "JSON";
myDS.ConnectionProperties.ConnectString = "jsondoc=https://demodata.grapecity.com/northwind/api/v1/Customers";
return myDS;
}

In the myDataSet() method, we retrieve the data. We also need to add each field to the data set. In the code below, we are also creating a countryFilter to filter the data set based on the hidden parameter created earlier.

private GrapeCity.ActiveReports.PageReportModel.IDataSet myDataSet()
{
var myDSet = new GrapeCity.ActiveReports.PageReportModel.DataSet();
var myQuery = new GrapeCity.ActiveReports.PageReportModel.Query();
myDSet.Name = "MyDataSet";
myQuery.DataSourceName = "MyDataSource";
myQuery.CommandText = "$.[*]";
myDSet.Query = myQuery;

//Create individual fields
var country = new GrapeCity.ActiveReports.PageReportModel.Field("country", "country", null);
var compName = new GrapeCity.ActiveReports.PageReportModel.Field("companyName", "companyName", null);
var contactName = new GrapeCity.ActiveReports.PageReportModel.Field("contactName", "contactName", null);
var address = new GrapeCity.ActiveReports.PageReportModel.Field("address", "address", null);
var cityName = new GrapeCity.ActiveReports.PageReportModel.Field("city", "city", null);
var phone = new GrapeCity.ActiveReports.PageReportModel.Field("phone", "phone", null);

//Create filter to use Parameter
var countryFilter = new GrapeCity.ActiveReports.PageReportModel.Filter
{
FilterExpression = "=Fields!country.Value",
FilterValues = { "=Parameters!selectedCountry.Value" }
};

//Add fields and filter to the dataset
myDSet.Fields.Add(country);
myDSet.Fields.Add(compName);
myDSet.Fields.Add(contactName);
myDSet.Fields.Add(address);
myDSet.Fields.Add(cityName);
myDSet.Fields.Add(phone);
myDSet.Filters.Add(countryFilter);

return myDSet;
}

Pass the Report to the JSViewer Using CustomStore

To put everything together, modify the Startup.cs file to pass the report from our custom ReportDefinition class to the JSViewer. To do so, utilize the UseCustomStore setting of the Reporting service in the Configure method as follows:

app.UseReporting(settings =>
{
settings.UseEmbeddedTemplates(EmbeddedReportsPrefix, Assembly.GetAssembly(GetType()));
settings.UseCustomStore(GetReport);
settings.UseCompression = true;
});

Create a GetReport() method that will call our ReportDefinition class and return the RDL report:

private object GetReport(string arg)
{
if (!IsReport(arg))
return null;
var reportDef = new Reports.ReportDefinition();
return reportDef.rdlReport;
}

Finally, run the project and observe the output below:

In conclusion, creating an RDL report in C# using ActiveReports is a powerful and flexible way to generate dynamic reports. By following the steps outlined in this blog, you can set up a project, create and style a report, bind data, and manage user interactions effectively. We walked through the process of creating a list of countries that, when selected, display a report of customers from the chosen country with their contact information. This included setting up the project, creating the report layout, adding a table, setting up parameters, and binding data from a JSON source.

By using the JSViewer, we were able to seamlessly pass user input to filter data and render the report. This method ensures that the report is interactive and meets the specific needs of the user.

The practical implementation covered in this guide demonstrates how to leverage ActiveReports to create robust and dynamic reporting solutions. If you are ready to get started, download a free trial of ActiveReports.NET today. Download this sample for detailed implementation and code samples. This will help you explore the capabilities of ActiveReports further and integrate it into your projects effectively. Happy reporting!

Originally published at https://developer.mescius.com on July 17, 2024.

--

--

MESCIUS inc.
MESCIUS inc.

We provide developers with the widest range of Microsoft Visual Studio components, IDE platform development tools, and applications.