DEV Community

Cover image for How to Create an RDL Report in .NET C# Code
Chelsea Devereaux for MESCIUS inc.

Posted on • Originally published at developer.mescius.com

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

What You Will Need

  • Visual Studio 2017-2022
  • ActiveReports.NET

Controls Referenced

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).

Rendered creating rdl report

This blog will show you how to:

Set Up the Project

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

Configure new project

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:

Solution explorer

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>
Enter fullscreen mode Exit fullscreen mode

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

    <body onload="populateList()">
Enter fullscreen mode Exit fullscreen mode

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();
          }
Enter fullscreen mode Exit fullscreen mode

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]}])}
    }
Enter fullscreen mode Exit fullscreen mode

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;
        }
    }
Enter fullscreen mode Exit fullscreen mode

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;
Enter fullscreen mode Exit fullscreen mode

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);
Enter fullscreen mode Exit fullscreen mode

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);
Enter fullscreen mode Exit fullscreen mode

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"
    };
Enter fullscreen mode Exit fullscreen mode

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;
Enter fullscreen mode Exit fullscreen mode

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" });
Enter fullscreen mode Exit fullscreen mode

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;
Enter fullscreen mode Exit fullscreen mode

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"}
    });
Enter fullscreen mode Exit fullscreen mode

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" });
Enter fullscreen mode Exit fullscreen mode

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

    rdlReport.Report.Body.ReportItems.Add(customersTable);
Enter fullscreen mode Exit fullscreen mode

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);
Enter fullscreen mode Exit fullscreen mode

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());
Enter fullscreen mode Exit fullscreen mode

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;
    }
Enter fullscreen mode Exit fullscreen mode

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;
    }
Enter fullscreen mode Exit fullscreen mode

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;
    });
Enter fullscreen mode Exit fullscreen mode

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;
    }
Enter fullscreen mode Exit fullscreen mode

Finally, run the project and observe the output below:

Final RDL report

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 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!

Top comments (0)