Click here to Skip to main content
Click here to Skip to main content

An Open Source RDL Engine

, 20 Dec 2010 CPOL
Rate this:
Please Sign up or sign in to vote.
An Open Source RDL engine for rendering reports to WinForms or ASP.NET

Introduction

The Sawiki RDL Reporting engine is used to render RDL reports to an ASP.NET or Winforms viewer. It can also be export rendered reports to XLS, PFD, or CSV format files.

The RDL Engine reads RDL files created in Microsoft Visual Studio, connects to the referenced database, collects parameter information and renders the resulting report. It currently supports all RDL features with the exception of 3D charts, Columns, Recursive hierarchies, Document Maps, and Fixed Headers. It includes full VB.NET support including importing external libraries.

This is a lightweight high speed report renderer and includes an RDL compiler to further improve performance of report projects. It is useful to anyone wishing to deploy Microsoft Reporting Services report to a web site without having to pay for a SQL Server license, or to deploy reports in a WinForms applications.

Background

This project was started as a means of including RDL reports into a web site without having to pay Microsoft for a SQL Server licence for the web server. Also I didn't like the way the Microsoft ASP.NET report viewer worked. I spent some time with the open source project RDL Project 3 but was unhappy with the partial VB interpreter and the complex rendering algorithms.

The Engine uses the VBCodeProvider class from Microsoft.VisualBasics namespace to compile any included source and expressions into an assembly. Each function in the assembly is put into a list of delegates which can be called by index during report processing. The only expressions that can't be compiled directly are ones including the aggregate functions like Sum, Avg, etc. For these, the VB source code from the RDL report is modified using regular expressions to wrap any aggregate function call into an iterator.

Rendering is done to an intermediate model and then rendered to the final form. The intermediate model is represented by the GenericRender class which is returned by the Report.Run method. The GenericRender represents a simple box model which can be easily translated to one of the final rendering classes. These include RenderToHtml, RenderPagesToHtml, RenderToText, RenderToCsv, RenderToXls, and RenderPagesToPdf. The WinForms viewer works directly with the GenericRender class. The simple box model of the GenericRender class allows simple rendering to the various final forms which is evidenced by the RenderToText class being less than 100 lines of total code.

Using the Code

The RDL Engine includes four elements:

  • RDLEngine - The base library which includes the RDL interpreter and rendering engine. This needs to be included in any reporting project.
  • RDLAsp - The ASP.NET library including a report viewer control, a parameters control, a print function, and an export function.
  • RDLViewer - The WinForms library including a report viewer, a parameters control, a parameters dialog, print and export functions
  • RDLCompile - The RDL compiler for compiling an RDL report into a .NET assembly.

To read in an RDL report, set some parameters and write the rendered report out to PDF and XLS use the following:

// Create a new Report object and load an RDL report definition
Rdl.Engine.Report rpt = new Rdl.Engine.Report();
FileStream fs = new FileStream("Product Line Sales.rdl", FileMode.Open);
rpt.Load(fs, ".");
fs.Close();

// Set parameters
rpt.ReportParameters["Category"].Value = 1;
rpt.ReportParameters["StartDate"].Value = DateTime.Now;
rpt.ReportParameters["EndDate"].Value = DateTime.Now.AddMonths(-1);

// Render the report
Rdl.Render.GenericRender render = rpt.Run();

// Export to XLS and write to a file
Rdl.Render.RenderToXls xlsExport = new Rdl.Render.RenderToXls();
string xls = xlsExport.Render(render, false);
StreamWriter sw = File.CreateText("Product Line Sales.xls");
sw.Write(xls);
sw.Close();

// Export to PDF and write to a file
PageRender pr = new Rdl.Render.PageRender();
pr.Render(render);
Rdl.Render.RenderPagesToPdf pdfExport = new Rdl.Render.RenderPagesToPdf();
string pdf = pdfExport.Render(render, pr);
sw = File.CreateText("Product Line Sales.pdf");
sw.Write(pdf);
sw.Close();

The following ASP.NET page includes a ReportViewer control and a Parameters control. When Button6 is pressed, the Parameters control is loaded with the Product Line Sales report. The Parameters control includes a View button which when pressed triggers the ViewReport event in which the report is rendered and loaded into the ReportViewer control.

<%@ Page Language="C#" MasterPageFile="~/Sawiki.master" 
AutoEventWireup="true" CodeFile="Samples.aspx.cs" 
Inherits="_Samples" Title="Sawiki Software Samples" %>
<%@ Register TagPrefix="uc" Assembly="RdlAsp" 
Namespace="RdlAsp" %>
<%@ Register Assembly="AjaxControlToolkit" 
Namespace="AjaxControlToolkit" TagPrefix="cc1" %>
<%@ Register Assembly="System.Web.Extensions, 
Version=1.0.61025.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35"
    Namespace="System.Web.UI" TagPrefix="asp" %>
<asp:Content ID="Content1" ContentPlaceHolderID="
ContentPlaceHolder1" Runat="Server">
<asp:ScriptManager ID="ScriptManager1" runat="server">
</asp:ScriptManager>
<div>
    <asp:Button ID="Button6" runat="server" 
    OnClick="ProductLineSales_Click" Text="Product Line Sales" />
    <table>
        <tr>
            <td>
            <uc:Parameters ID="ReportParameters" 
            runat="server" OnViewReport="
            ReportParameters_ViewReport" />
            </td>
        </tr>
        <tr>
            <td>
            <uc:ReportViewer ID="ReportViewer" runat="server" />
            </td>
        </tr>
    </table>
     
</div>
</asp:Content>

With the code behind:

protected void ReportParameters_ViewReport
	(object sender, RdlAsp.ViewReportEventArgs e)
{
    // When the ParameterEntry control posts this event 
    // render the passed report and load the ReportViewer with it
    Rdl.Engine.Report rpt = e.Report;
    Rdl.Render.GenericRender render = rpt.Run();
    ReportViewer.SetReport(render);
}

protected void ProductLineSales_Click(object sender, EventArgs e)
{
    // Load the report
    Rdl.Engine.Report rpt = new Rdl.Engine.Report();
    string path = Request.MapPath("SampleReports\\Product Line Sales.rdl");
    FileStream fs = new FileStream(path, FileMode.Open);
    rpt.Load(fs, System.IO.Path.GetDirectoryName(path));
    
    // Put the report into the Parameters control
    ReportParameters.SetReport(rpt);
    ReportViewer.SetReport(null);
}

In the following WinForms example, it is assumed that you have a form with a Parameters control, a ReportViewer control, and a button named btnEmployeeSalesSummary. When the button is pressed, the Employee Sales Summary report is loaded and put into the Parameters control. When the Parameters view button is pressed, the ViewReport event is raised where the report is rendered and put into the ReportViewer control. In this example, the InitializeDataSet event is registered which may be used if the programmer wants to substitute a custom data table for the one defined in the RDL report.

private void Form1_Load(object sender, EventArgs e)
{
    parametersEntry1.ViewReport += 
	new EventHandler<RdlViewer.ParametersEntry.ViewReportEventArgs>(ViewReport);
}

static void rpt_InitializeDataSet(object sender, 
	Rdl.Runtime.InitializeDataSetEventArgs args)
{
    switch(args.DataSetName)
    {
        case "SalesEmps":
            // You could replace the default data with a 
            // custom data table for any of the named datasets here.
            //e.dt = {your custom datatable}
            break;
        default:
            break;
    }
}

private void ViewReport(object sender, RdlViewer.ParametersEntry.ViewReportEventArgs args)
{
    // When the ParameterEntry control posts this event 
    // render the passed report and load the ReportViewer with it
    Rdl.Render.GenericRender render = args.Report.Run();
    reportViewer1.SetReport(render);
}

private void btnEmployeeSalesSummary_Click(object sender, EventArgs e)
{
    // Load the report and put it into the ParameterEntry control
    Rdl.Engine.Report rpt = new Rdl.Engine.Report();
    rpt.Load(new FileStream(@"Employee Sales Summary.rdl", 
		FileMode.Open, FileAccess.Read, FileShare.Read),
        @".");
    rpt.InitializeDataSet += rpt_InitializeDataSet;
    
    parametersEntry1.SetReport(rpt);
}

References

The home of the SawikiSoft RDL Engine project. You can find viewable sample reports and the current source code at this site.

History

  • 17th December, 2010: Initial version

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)

Share

About the Author

Mike Emerson
Software Developer (Senior) Sawiki Software
United States United States
I have been a professional software developer for 25+ years, most of it supporting the business community of Maine. I have been working with MS dotnet since 1.0 beta. I organized Sawiki Software LLC as an outlet for some open source software that I have been working on.

Comments and Discussions

 
QuestionNice article. But, unable to access your website Sawikifsoft PinmemberMember 17933013-Nov-13 10:35 
GeneralMy vote of 5 PinmemberVitorHugoGarcia26-May-13 23:35 
Questionrdlc report(custom export) Pinmembersairam_1978@yahoo.com16-May-13 4:47 
GeneralRDL vs ASP PinmemberMember 98218178-Feb-13 10:27 
GeneralMy vote of 1 PinmemberKoru.nl17-Jul-11 3:03 
QuestionError in report parsing Pinmembermotagaly24-Jun-11 4:24 
GeneralDatabase credentials [modified] PinmemberMember 446970825-Mar-11 5:19 
Using the sample script to write a PDF, the file is created but it's empty when I open it in Acrobat. I can run the report in ReportBuilder 2 with no problem.

modified on Friday, March 25, 2011 11:33 AM

GeneralShame you built it with a licensed 3rd party tool. PinmemberTomVan27-Dec-10 11:46 
GeneralRe: Shame you built it with a licensed 3rd party tool. [modified] PinmemberMike Emerson1-Jan-11 9:26 
AnswerRe: Shame you built it with a licensed 3rd party tool. PinmemberMike Emerson3-Jan-11 10:19 
Generalits nice PinmemberPranay Rana26-Dec-10 23:40 
GeneralMy vote of 4 PinmemberMarco Schmittnägel20-Dec-10 20:51 

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

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

| Advertise | Privacy | Mobile
Web03 | 2.8.141015.1 | Last Updated 20 Dec 2010
Article Copyright 2010 by Mike Emerson
Everything else Copyright © CodeProject, 1999-2014
Terms of Service
Layout: fixed | fluid