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:
.NET:
Math (Abs , Cos , Sin , Log , ...)
String (Concat , Format , IndexOf , Substring , ...)
Convert (ToDateTime , ToDouble , ToDecimal , ...)
Arithmetic:
+ , - , / , * , ^ , %
- decimal and floating point arithmetic
Logical:
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.
='1.0' ='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 -->
Using the code
There are several ways that you can use and explore the RDL Project:
- 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.
- 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.
- 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).
- 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.
- 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.
private void DoRender(string dir, string[] files, string[] types)
{
string source;
Report report;
int index;
ListDictionary ld;
string file;
foreach (string filename in files)
{
index = filename.LastIndexOf('?');
if (index >= 0)
{
ld = this.GetParmeters(filename.Substring(index));
file = filename.Substring(0, index);
}
else
{
ld = null;
file = filename;
}
source = this.GetSource(file);
if (source == null)
continue;
report = this.GetReport(source, file);
if (report == null)
continue;
report.RunGetData(ld);
string fileNoExt;
fileNoExt = dir + Path.GetFileNameWithoutExtension(file);
foreach (string stype in types)
{
SaveAs(report, fileNoExt+"."+stype, stype);
}
}
}
private ListDictionary GetParmeters(string parms)
{
ListDictionary ld= new ListDictionary();
if (parms == null)
return ld;
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)
{
RDLParser rdlp;
Report r;
try
{
rdlp = new RDLParser(prog);
r = rdlp.Parse();
if (r.rl.MaxSeverity > 0)
{
Console.WriteLine("{0} has the following errors:", file);
foreach (string emsg in r.rl.ErrorItems)
{
Console.WriteLine(emsg);
}
int severity = r.rl.MaxSeverity;
r.rl.Reset();
if (severity > 4)
{
r = null;
returnCode = 8;
}
}
}
catch(Exception e)
{
r = null;
Console.WriteLine(e.Message);
returnCode = 8;
}
return r;
}
private void SaveAs(Report report, string FileName, string type)
{
string ext = type.ToLower();
OneFileStreamGen sg=null;
try
{
sg = new OneFileStreamGen(FileName, true);
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.