Click here to Skip to main content
15,881,852 members
Articles / Web Development / ASP.NET

An Open Source RDL Engine

Rate me:
Please Sign up or sign in to vote.
4.77/5 (12 votes)
20 Dec 2010CPOL3 min read 83.5K   3.5K   55   13
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:

C#
// 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.

ASP.NET
<%@ 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:

C#
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.

C#
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)


Written By
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

 
QuestionException: Requested value 'ElementNormal' was not found. Pin
Andrew Friedl24-Sep-15 7:02
Andrew Friedl24-Sep-15 7:02 
This occurred in ParseAttribute(XmlNode attr). The report rdl dates back a few years. Is this project still supported?
QuestionNice article. But, unable to access your website Sawikifsoft Pin
Sau00213-Nov-13 10:35
Sau00213-Nov-13 10:35 
GeneralMy vote of 5 Pin
_Vitor Garcia_26-May-13 23:35
_Vitor Garcia_26-May-13 23:35 
Questionrdlc report(custom export) Pin
sairam_1978@yahoo.com16-May-13 4:47
sairam_1978@yahoo.com16-May-13 4:47 
GeneralRDL vs ASP Pin
Member 98218178-Feb-13 10:27
Member 98218178-Feb-13 10:27 
GeneralMy vote of 1 Pin
Koru.nl17-Jul-11 3:03
Koru.nl17-Jul-11 3:03 
QuestionError in report parsing Pin
motagaly24-Jun-11 4:24
motagaly24-Jun-11 4:24 
GeneralDatabase credentials [modified] Pin
Member 446970825-Mar-11 5:19
Member 446970825-Mar-11 5:19 
GeneralShame you built it with a licensed 3rd party tool. Pin
TomVan27-Dec-10 11:46
TomVan27-Dec-10 11:46 
GeneralRe: Shame you built it with a licensed 3rd party tool. [modified] Pin
Mike Emerson1-Jan-11 9:26
Mike Emerson1-Jan-11 9:26 
AnswerRe: Shame you built it with a licensed 3rd party tool. Pin
Mike Emerson3-Jan-11 10:19
Mike Emerson3-Jan-11 10:19 
Generalits nice Pin
Pranay Rana26-Dec-10 23:40
professionalPranay Rana26-Dec-10 23:40 
GeneralMy vote of 4 Pin
User 712520420-Dec-10 20:51
User 712520420-Dec-10 20:51 

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.