Click here to Skip to main content
15,867,704 members
Articles / Database Development / SQL Server
Article

Project RDL - Open Source Report Definition Language implementation in C#

Rate me:
Please Sign up or sign in to vote.
4.83/5 (29 votes)
9 Jan 20057 min read 363.3K   7.8K   160   55
The RDL Project is an open source (GPL) implementation of the RDL for the .NET environment created by fyiReporting Software. RDL is an XML based language created by Microsoft with the goal of promoting interoperability of reporting products. Project RDL is a compact implementation of RDL.

Simple Chart Report

Introduction

The RDL Project is an open source (GPL) C# implementation of the Report Definition Language (RDL) for the .NET environment, by fyiReporting Software.

RDL is an XML based language created by Microsoft with the goal of promoting interoperability of reporting products. Microsoft implemented RDL as part of the Microsoft SQL Server Reporting Services product. The RDL Project is a compact implementation of this powerful reporting language. It provides interoperability with Microsoft Reporting Services reports, letting you use reports in any of your .NET applications.

Warning: The download is an alpha version and should be used for experimentation purposes only. Later versions will be more fully tested and debugged.

Background

Overview of implemented RDL capabilities

The Report Definition Language (RDL) is a powerful and flexible language for defining reports. The specification for RDL runs over 100 pages. The RDL Project implements most of that functionality. While this article will barely touch the breadth of its capabilities, below is a list of some of the reporting capabilities that RDL enables:

Capability

Description

Charts

2D business graphics

  • Column (plain, stacked, percent stacked)
  • Bar (plain, stacked, percent stacked)
  • Line (plain, smooth)
  • Pie (plain, exploded)
  • Area (plain, stacked)
  • Doughnut

Tables

Presents report items in a tabular format

  • Table groups
  • Multiple header, footer, detail rows

List

Allows absolute positioning of report items

Matrix

Also known as cross tabulation.

  • Multi-level grouping of rows and columns

Output rendering

Reports can be rendered using multiple formats.

  • PDF
  • XML
  • .NET control
  • Printed reports

Datasources

Relational databases:

  • Microsoft SQL Server
  • Microsoft OLE DB Provider
  • ODBC - tested with MySQL

Expressions

Expression language based on VB.NET functions and expressions. Including the following:

Financial:

  • DDB, FV, IPmt, NPer, Pmt, PV, Rate, SLN, SYD

Aggregate:

  • sum, avg, count, max, min, stdev, stdevp, var, varp, running value of all aggregate functions

Control:

  • iif, choose, switch

.NET:

  • Math (Abs, Cos, Sin, Log, ...)
  • String (Concat, Format, IndexOf, Substring, ...)
  • Convert (ToDateTime, ToDouble, ToDecimal, ...)

Arithmetic:

  • +, -, /, *, ^, %
  • decimal and floating point arithmetic

Logical:

  • and, or, not

User written functions:

  • Anything you can imagine supporting both static and instance based methods.

What’s not there

The RDL Project doesn’t attempt to be API compatible with Microsoft SQL Server Reporting Services. The primary goal is that reports that run on Reporting Services will also work with the RDL Project. There are some limitations in the current alpha version. Two main absences are no 3D graphs and no subreport support. Again, please be aware that this is an alpha version that will require several months of testing and bug fixing before the reports generated can be fully trusted. Please stay tuned to future versions.

Modules

The RDL Project consists of a number of executables that provide (and demonstrate) various capabilities.

Component

Name

Description

RDL engine

RdlEngine.dll

Provides the reporting engine and rendering services. This is the base engine that all other components require.

.NET control

RdlViewer.dll

Provides a .NET control for embedding in .NET applications. Displays RDL reports, and provides methods for printing and saving to HTML, PDF, and XML.

RDL reader

RdlReader.exe

An MDI application that provides Adobe Reader like capabilities for RDL reports. This application shows some of the functionality supported by the .NET RDL control.

RDL designer

RdlDesigner.exe

An MDI application providing simple report creation, editing and previewing.

RDL desktop

RdlDesktop.exe

A small desktop report server providing browser access to your reports. Point your browser to the URL http://localhost:8080/. The port 8080 is the default and can be modified in the config.xml file. Also specified in the config file is the directory which contains the report files to be served.

RDL batch

RdlCmd.exe

Batch command executable for creating PDF, XML, HTML files from RDL files.

Sample RDL

The chart shown at the beginning of the article was created by the RDL listed below. As you can see, RDL (and XML, in general) is not especially compact. The RdlDesigner executable has some wizard support to automatically generate table and list reports from a database (SQL Server, MySQL via ODBC) but does not currently include a WYSIWYG designer. Fortunately, you can create RDL files using other tools, most notably Microsoft's designer that comes with Reporting Services, and run them using the RDL Project's reporting engine.

XML
<?xml version='1.0' encoding='UTF-8'?>
<Report Name=''> 
    <PageHeight>8.5in</PageHeight>
    <PageWidth>11in</PageWidth>
    <LeftMargin>.5in</LeftMargin>
    <Description>Column Chart</Description>
    <Author>fyiReporting Software, LLC</Author>
    <DataSources>
        <DataSource Name='DS1'>
            <ConnectionProperties> 
                <DataProvider>SQL</DataProvider>
                change to this for sql server -->
                <ConnectString>
                  Server=(local)\VSDotNet;DataBase=Northwind;Integrated 
                  Security=SSPI;Connect Timeout=5</ConnectString>
            </ConnectionProperties>
        </DataSource>
    </DataSources>
    <DataSets>
        <DataSet Name='Data'>
            <Query>
                <DataSourceName>DS1</DataSourceName>
                <CommandText>SELECT Category, Year, 
                       Sales FROM CategorySalesView</CommandText>
            </Query>
            <Fields>
                <Field Name='Category'> 
                    <DataField>Category</DataField>
                </Field>
                <Field Name='Year'> 
                    <DataField>Year</DataField>
                </Field>
                <Field Name='Sales'> 
                    <DataField>Sales</DataField>
                </Field>
            </Fields>
        </DataSet>
    </DataSets>
<Body>
  <ReportItems>
     <Chart Name="column_chart">
        <Height>7 in</Height>
        <Width>10 in</Width>
        <Style>
          <BackgroundGradientEndColor>Gray</BackgroundGradientEndColor>
          <BackgroundGradientType>LeftRight</BackgroundGradientType>
          <BackgroundColor>White</BackgroundColor>
        </Style>
        <Legend>
          <Visible>true</Visible>
          <Style>
            <WritingMode>lr-tb</WritingMode>
            <BorderStyle>
              <Default>None</Default>
            </BorderStyle>
            <BorderWidth><Default>1pt</Default></BorderWidth>
            <TextAlign>Left</TextAlign>
          </Style>
          <Position>BottomCenter</Position>
          <Layout>Row</Layout>
        </Legend>
        <Palette>Default</Palette>
        <ChartData>
          <ChartSeries>
            <DataPoints>
              <DataPoint>
                <DataValues>
                  <DataValue>
                    <Value>=Sum(Fields!Sales.Value)</Value>
                  </DataValue>
                </DataValues>
                <DataLabel>
                  <Style>
                    <Format>$#,###</Format>
                    <Color>Red</Color>
                    <VerticalAlign>Middle</VerticalAlign>
                  </Style>
                  <Visible>true</Visible>
                </DataLabel>
                <Marker />
              </DataPoint>
            </DataPoints>
          </ChartSeries>
        </ChartData>
        <CategoryAxis>
          <Axis>
            <MajorGridLines>
              <Style>
                <BorderStyle>
                  <Default>Solid</Default>
                </BorderStyle>
              </Style>
            </MajorGridLines>
            <MinorGridLines>
              <Style>
                <BorderStyle>
                  <Default>Solid</Default>
                </BorderStyle>
              </Style>
            </MinorGridLines>
            <MajorInterval>1</MajorInterval>
            <MinorInterval>1</MinorInterval>
            <Margin>true</Margin>
            <Visible>true</Visible>
            <Scalar>true</Scalar>
            <Title>
              <Caption>Years</Caption>
              <Style>
                <FontWeight>Bolder</FontWeight>
                <FontSize>20pt</FontSize> 
                <FontStyle>Normal</FontStyle>
              </Style>
            </Title>
            <Style>
               <FontWeight>Bolder</FontWeight>
              <FontSize>15pt</FontSize> 
              <FontStyle>Italic</FontStyle>
            </Style>
            <MajorTickMarks>Cross</MajorTickMarks>
          </Axis>
        </CategoryAxis>
        <DataSetName>Data</DataSetName>
        <Type>Column</Type>
        <Top>0.375in</Top>
        <PageBreakAtEnd>true</PageBreakAtEnd>
        <Title>
          <Caption>Sales by Category</Caption>
          <Style>
            <WritingMode>rl-tb</WritingMode>
            <FontWeight>Bolder</FontWeight>
            <FontSize>20pt</FontSize> 
            <FontStyle>Normal</FontStyle>
          </Style>
        </Title>
        <CategoryGroupings>
          <CategoryGrouping>
            <DynamicCategories>
              <Grouping Name="column_chart_CategoryGroup">
                <GroupExpressions>
                  <GroupExpression>=Fields!Year.Value</GroupExpression>
                </GroupExpressions>
              </Grouping>
              <Label>=Fields!Year.Value</Label>
            </DynamicCategories>
          </CategoryGrouping>
        </CategoryGroupings>
        <SeriesGroupings>
          <SeriesGrouping>
            <DynamicSeries>
              <Grouping Name="column_chart_SeriesGroup">
                <GroupExpressions>
                  <GroupExpression>=Fields!Category.Value</GroupExpression>
                </GroupExpressions>
              </Grouping>
              <Label>=Fields!Category.Value</Label>
            </DynamicSeries>
          </SeriesGrouping>
        </SeriesGroupings>
        <Subtype>PercentStacked</Subtype>
        <PlotArea>
          <Style>
            <BorderStyle>
              <Default>Solid</Default>
            </BorderStyle>
            <BackgroundGradientEndColor>White</BackgroundGradientEndColor>
            <BackgroundGradientType>DiagonalRight</BackgroundGradientType>
            <BackgroundColor>Red</BackgroundColor>
          </Style>
        </PlotArea>
        <ValueAxis>
          <Axis>
            <Title>
              <Caption>Percentages</Caption>
              <Style>
                <WritingMode>tb-rl</WritingMode>
                <FontWeight>Bolder</FontWeight>
                <FontSize>20pt</FontSize> 
                <FontStyle>Normal</FontStyle>
              </Style>
            </Title>
            <Style>
              <Format>0%</Format>
            </Style>
            <MajorGridLines>
              <ShowGridLines>true</ShowGridLines>
              <Style>
                <BorderStyle>
                  <Default>Solid</Default>
                </BorderStyle>
                <BorderWidth>
                  <Default>1pt</Default>
                </BorderWidth>
              </Style>
            </MajorGridLines>
            <MinorGridLines>
              <Style>
                <BorderStyle>
                  <Default>Solid</Default>
                </BorderStyle>
              </Style>
            </MinorGridLines>
            <Visible>true</Visible>
            <MajorTickMarks>Cross</MajorTickMarks>
          </Axis>
        </ValueAxis>
      </Chart>
  </ReportItems>
</Body>
</Report>

Using the code

There are several ways that you can use and explore the RDL Project:

  1. Create RDL reports and use one of the executables (RdlReader, RdlDesigner, RdlCmd, RdlDesktop) to render the reports. This is the easiest way to become familiar with RDL and see if it provides the functionality you need for your reports.
  2. Embed the .NET control in your GUI application. To use the .NET control, you need to add a reference to the RdlViewer.dll and RdlEngine.dll in your project. You should then add RdlViewer.dll to your toolbox. Simply assigning a file name to the SourceFile property will cause your report to load. Alternatively, assign RDL XML to SourceRdl if you want to programmatically generate RDL and preview a report. Look at the code in the RdlReader project to see a simple example exploiting the printing, saving and other capabilities of the control.
  3. RdlCmd provides a simple example of how to directly call the reporting engine RdlEngine.dll. See the “Simple source example” below for a code example using this technique. One use for RdlCmd is to run reports in batch then upload the file(s) to your web site. This means that no report processing takes place dynamically from the web server lessening its load. Of course, this technique is only useful for reports whose rendered shelf life is fairly long (e.g., greater than 30 minutes).
  4. RdlDesktop provides a more complex example of how the RDL engine can be used in a multi-threaded environment. In general, a single report instance should be used by a single thread. Multiple threads can be used to allow multiple users to simultaneously render different reports. Caching of the rendered report (HTML, PDF, XML) allows greater throughput. This level of concurrency makes sense because the actual report is created only once and it is the rendered output that can be shared by multiple users.
  5. You might find various routines to be interesting in isolation. For example, the Financial.cs file in \RdlEngine\Functions contains static functions for the DDB, FV, IPmt, NPer, Pmt, PV, Rate, SLN and SYD functions.

Simple source example

The following code is a snippet from RdlCmd.cs that shows how to take a source report definition, compile it, obtain the data needed to create the report, and finally render it. Notice that the routine handles multiple input report definition files and can create one or more output renderings (HTML, PDF, and/or XML) from a single report.

C#
// Render the report files with the requested types
private void DoRender(string dir, string[] files, string[] types)
{
      string source;
      Report report;
      int index;
      ListDictionary ld;
      string file;

      foreach (string filename in files)
      {
            // Any parameters?  e.g.  file1.rdl?orderid=5
            index = filename.LastIndexOf('?');
            if (index >= 0)
            {
                  ld = this.GetParmeters(filename.Substring(index));
                  file = filename.Substring(0, index);
            }
            else
            {
                  ld = null;
                  file = filename;
            }

            // Obtain the source
            source = this.GetSource(file);
            // GetSource is omitted: all it does is read the file.

            if (source == null)
                  continue;  // error: process the rest of the files

            // Compile the report
            report = this.GetReport(source, file);
            if (report == null)
                  continue;  // error: process the rest of the files

            // Obtain the data passing any parameters
            report.RunGetData(ld);

            // Render the report in each of the requested types
            string fileNoExt;
            fileNoExt = dir + Path.GetFileNameWithoutExtension(file);

            foreach (string stype in types)
            {
                  SaveAs(report, fileNoExt+"."+stype, stype);
            }
      }     // end foreach files
}

// GetParameters creates a list dictionary
// consisting of a report parameter name and a value.
private ListDictionary GetParmeters(string parms)
{
      ListDictionary ld= new ListDictionary();
      if (parms == null)
            return ld; // dictionary will be empty in this case

      // parms are separated by &
      char[] breakChars = new char[] {'&'};
      string[] ps = parms.Split(breakChars);

      foreach (string p in ps)
      {
            int iEq = p.IndexOf("=");
            if (iEq > 0)
            {
                  string name = p.Substring(0, iEq);
                  string val = p.Substring(iEq+1);
                  ld.Add(name, val);
            }
      }
      return ld;
}

private Report GetReport(string prog, string file)
{
      // Now parse the file
      RDLParser rdlp;
      Report r;

      try
      {
            rdlp =  new RDLParser(prog);
            // RDLParser takes RDL XML and Parse compiles the report

            r = rdlp.Parse();
            if (r.rl.MaxSeverity > 0)
            {
                  // have errors fill out the msgs
                  Console.WriteLine("{0} has the following errors:", file);

                  foreach (string emsg in r.rl.ErrorItems)
                  {
                        Console.WriteLine(emsg);
                        // output message to console
                  }

                  int severity = r.rl.MaxSeverity;
                  r.rl.Reset();
                  if (severity > 4)
                  {
                        r = null; // don't return when severe errors
                        returnCode = 8;
                  }
            }
      }
      catch(Exception e)
      {
            r = null;
            Console.WriteLine(e.Message);
            returnCode = 8;
      }

      return r;
}

// Save the file.  The extension determines the type of file to save.
// "FileName" Name of the file to be saved to.
// "ext" Type of file to save.  Should be "pdf", "xml", "html".
private void SaveAs(Report report, string FileName, string type)
{
      string ext = type.ToLower();
      OneFileStreamGen sg=null;

      try
      {
            sg = new OneFileStreamGen(FileName, true);
            // overwrite with this name

            switch(ext)
            {
                  case "pdf":
                    report.RunRender(sg, OutputPresentationType.PDF);
                    break;
                  case "xml":
                    report.RunRender(sg, OutputPresentationType.XML);
                    break;
                  case "html": case "htm":
                    report.RunRender(sg, OutputPresentationType.HTML);
                    break;
                  default:
                    Console.WriteLine("Unsupported file " +
                      "extension '{0}'.  " +
                      "Must be 'pdf', 'xml' or 'html'", type);
                    returnCode = 8;
                    break;
            }
      }

      catch(Exception e)
      {
            Console.WriteLine(e.Message);
            returnCode = 8;
      }
      finally
      {
            if (sg != null)
            {
                  sg.CloseMainStream();
            }
      }
      return;
}

Points of Interest

This article touched on only a small part of the functionality in the RDL Project. If reporting (or printing) is one of the requirements for your applications, RDL may be a good solution for you. I hope you find the RDL Project useful for your own presentation needs. Please contact me with any comments you have.

References

  • The home of the RDL project - You’ll find the latest versions of the software at this site. In addition to the source, a Microsoft installation is available for installing just the binary modules. The software is updated on roughly a monthly basis.
  • The specification for RDL - This is the definitive definition of the language. It is well written, but like most specifications is not really good for learning the language.
  • Search for Reporting Services books - There are quite a few books written about Microsoft SQL Server Reporting Services. Unfortunately, most of these books don’t go into much detail about RDL syntax.

History

January, 2005 - first alpha version of the RDL Project is placed on the web.

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here


Written By
United States United States
Kim Sheffield is the founder of fyiReporting Software, LLC.

Comments and Discussions

 
QuestionAlternative: Check a new C# Open Source Database Reporting tool for .Net Pin
Member 107605537-May-14 23:21
Member 107605537-May-14 23:21 
QuestionrdlViewer asp.net vb Pin
Gianni Giacinto22-Jan-14 3:00
Gianni Giacinto22-Jan-14 3:00 
QuestionVery nice - where can I find the latest source code Pin
Sau00213-Nov-13 10:20
Sau00213-Nov-13 10:20 
Questionnice and cool Pin
jason zabakly2-Feb-13 3:24
jason zabakly2-Feb-13 3:24 
GeneralMy vote of 5 Pin
Manoj Kumar Choubey7-Feb-12 3:01
professionalManoj Kumar Choubey7-Feb-12 3:01 
Generalfyi Reporting in ASP.net for HTML Report Pin
shiva Maranur8-Nov-09 23:28
shiva Maranur8-Nov-09 23:28 
QuestionNeed to open new page without refreshing the existing page Pin
sridhar.talla24-Jan-09 20:04
sridhar.talla24-Jan-09 20:04 
Generalhi Pin
Nazneen Zahid19-Aug-08 0:19
Nazneen Zahid19-Aug-08 0:19 
GeneralRe: hi Pin
Kim Sheffield19-Aug-08 6:12
Kim Sheffield19-Aug-08 6:12 
GeneralRe: hi Pin
Nazneen Zahid20-Aug-08 1:25
Nazneen Zahid20-Aug-08 1:25 
hi
thanks for reply
nw i m able to use but again i m facing problem
i entered new entry in my database
and wana see these entries in my report, this is my problem
report is not shown updated database
its shown only those values when i created report
plz reply
what i hv to do for this problem
GeneralRe: hi Pin
Kim Sheffield20-Aug-08 8:44
Kim Sheffield20-Aug-08 8:44 
GeneralGraphic.DrawString toTextRenderer.DrawText Pin
Savun Cheam6-Apr-08 18:26
Savun Cheam6-Apr-08 18:26 
GeneralRe: Graphic.DrawString toTextRenderer.DrawText Pin
Kim Sheffield7-Apr-08 6:24
Kim Sheffield7-Apr-08 6:24 
GeneralRe: Graphic.DrawString toTextRenderer.DrawText Pin
Savun Cheam7-Apr-08 15:42
Savun Cheam7-Apr-08 15:42 
GeneralRe: Graphic.DrawString toTextRenderer.DrawText Pin
Kim Sheffield8-Apr-08 3:51
Kim Sheffield8-Apr-08 3:51 
GeneralRDL question Pin
Paddy Boyd20-Sep-07 22:37
Paddy Boyd20-Sep-07 22:37 
GeneralRe: RDL question Pin
Kim Sheffield21-Sep-07 4:16
Kim Sheffield21-Sep-07 4:16 
GeneralInstalling the Custom Report Item Type Pin
John Ulven16-Feb-07 5:14
John Ulven16-Feb-07 5:14 
GeneralRe: Installing the Custom Report Item Type Pin
Kim Sheffield17-Feb-07 6:26
Kim Sheffield17-Feb-07 6:26 
QuestionRDLC ? Pin
polymorphism7-Feb-07 5:50
polymorphism7-Feb-07 5:50 
AnswerRe: RDLC ? Pin
Kim Sheffield7-Feb-07 8:41
Kim Sheffield7-Feb-07 8:41 
QuestionRe: RDLC ? Pin
polymorphism7-Feb-07 20:36
polymorphism7-Feb-07 20:36 
AnswerRe: RDLC ? Pin
Kim Sheffield8-Feb-07 4:35
Kim Sheffield8-Feb-07 4:35 
GeneralCustom Report Item Pin
mambwe5-Feb-07 15:38
mambwe5-Feb-07 15:38 
GeneralRe: Custom Report Item Pin
Kim Sheffield6-Feb-07 4:28
Kim Sheffield6-Feb-07 4:28 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.