Examples

Reports Using LayoutEngine and Designer

Beginning with Core Suite Version 12, DynamicPDF redesigned DynamicPDF Designer from the ground up. DynamicPDF Core Suite's LayoutEngine and DynamicPDF Designer Online both make it easy to create reports based on your business objects, JSON, or directly from a database using SQL.

Here, we demonstrate creating a PDF from a DLEX file and layout data from:

  • a JSON document,
  • a business object hierarchy,
  • SQL that outputs JSON,
  • and SQL results directly.

Using JSON Layout Data

Let's first obtain the needed layout data from a JSON document (subreport.json available from the GitHub project). The following is a snippet from the JSON document.

"ProductsByCategory": [
{
    "Name": "Beverages",
    "Products": [
    {
        "ProductID": 1,
        "ProductName": "Chai",
        "QuantityPerUnit": "10 boxes x 20 bags",
        "Discontinued": false,
        "UnitPrice": 18
    },
...

Note that the Product element is anonymous. Refer to JSON and JSON Required Formatting for more information on creating LayoutEngine compliant JSON.

The following example illustrates creating a PDF using JSON layout data.

static void JsonVersion(String dlexString, String jsonString)
{
    string outputPdf = BASE_PATH + "subreport_json_output.pdf";
    DocumentLayout docLayout = new DocumentLayout(dlexString);
    LayoutData layoutData = new LayoutData(
     JsonConvert.DeserializeObject(
         File.ReadAllText(jsonString)
     ));
    Document document = docLayout.Layout(layoutData);
    document.Draw(outputPdf);
}

The example first creates a new DocumentLayout instance by loading the DLEX document (subreport.dlex available from the GitHub project). And then deserializing the JSON document into a .NET object hierarchy (Json.NET deserialization documentation). It loads the resulting objects into a LayoutData* instance, representing the data used to layout the document. It then creates a new Document instance by combining the DLEX instructions and LayoutData to produce a PDF.

Using JSON as layout data is the easiest and most flexible way to work with DLEX to create PDF reports.

Using Business Objects

Often you have your own business objects that you wish to use to supply data to a report. Let's illustrate creating a PDF using an user-defined object hierarchy. The code example has two classes, Category and Product.

class Category
{
    public string Name;
    public List<Product> Products;
}

class Product
{
    public int ProductID;
    public string ProductName;
    public string QuantityPerUnit;
    public Boolean Discontinued;
    public double UnitPrice;
}

The example then creates a List from the classes and uses it to process the DLEX file.

private static void NameValuesExample(String dlexString)
{
    DocumentLayout documentLayout = new DocumentLayout(dlexString);
    List<Category> productsByCategory = new List<Category>();
    Category a = new Category
    {
        Name = "Beverages",
        Products = new List<Product>() {
        	new Product { 
            	ProductID = 1, ProductName = "Chai",
            	QuantityPerUnit = "10 boxes x 20 bags",
            	Discontinued = false, UnitPrice = 12.22
        	},
        	new Product { 
            	ProductID = 2, ProductName = "Chang",
            	QuantityPerUnit = "5 boxes x 10 bags",
            	Discontinued = true, UnitPrice = 9.99
        	} 
        }
    };

    Category b = new Category
    {
        Name = "Condiments",
        Products = new List<Product>() {
            new Product { 
                ProductID = 3, ProductName = "Aniseed Syrup", 
                QuantityPerUnit = "20 boxes x 2 bottles",
                Discontinued = true, UnitPrice = 3.92
            },
            new Product { 
                ProductID = 4, ProductName = "Chef Anton's Cajun Seasoning", 
                QuantityPerUnit = "10 boxes x 10 containers", 
                Discontinued = false, UnitPrice = 3.23
            } 
        }
    };
    
    productsByCategory.Add(a);
    productsByCategory.Add(b);

    LayoutData layoutData = new LayoutData();
    layoutData.Add("ProductsByCategory", productsByCategory);

    Document document = documentLayout.Layout(layoutData);
      document.Draw(Util.GetPath("Output/subrep-object_output.pdf"));
}

The LayoutData instance loads the list of Category instances - each of which has a list of Products - and uses the data and DLEX file to create a PDF.

Using Database Layout Data

Although using a JSON document or a business object hierarchy is an easy way to get layout data, obtaining the data from a database is often more feasible. The following two examples illustrate obtaining data directly from the Northwinds database.

Refer to the blog post: Creating PDF Reports with Data (SQL) for more information on using SQL with DLEX to create PDFs.

The JSON document provides the needed tables and columns from the Northwinds database.

"ProductsByCategory": [
{
    "Name": "Beverages",
    "Products": [
    {
        "ProductID": 1,
        "ProductName": "Chai",
        "QuantityPerUnit": "10 boxes x 20 bags",
        "Discontinued": false,
        "UnitPrice": 18
    },
...

The relevant tables are Categories and Products.

Translate the JSON to a SQL SELECT statement to obtain a Product listing grouped by Category.

select CategoryName Name, ProductID, ProductName, QuantityPerUnit, Discontinued, UnitPrice 
from Products, Categories as ProductsByCategory 
where Products.CategoryID = ProductsByCategory.CategoryID
order by CategoryName

Note that we provided the alias Name for CategoryName and ProductsByCategory for Categories. The aliases are because the DLEX and original JSON document specified these names.

Using Database Layout Data (JSON)

The first database example we provide creates a JSON document in memory from a SQL query. In the following example, we query the data using SQL and format the output as JSON.

static void DatabaseVersionWithJson(String dlexString)
{
    string outputPdf = BASE_PATH + "subreport_db_json_output.pdf";
    string sql = "select CategoryName Name, ProductID, ProductName, " 
        + "QuantityPerUnit, Discontinued, UnitPrice "
        + "from Products, Categories as ProductsByCategory "
        + "where Products.CategoryID = ProductsByCategory.CategoryID "
        +"order by CategoryName for json auto, root('ProductsByCategory')";
    var jsonResult = new StringBuilder();
    using (var conn = new SqlConnection(CONNECTION_STRING))
    {
        using (var cmd = new SqlCommand(sql, conn))
        {
            conn.Open();
            var reader = cmd.ExecuteReader();
            if (!reader.HasRows)
            {
                jsonResult.Append("[]");
            }
            else
            {
                while (reader.Read())
                {
                    jsonResult.Append(reader.GetValue(0).ToString());
                }
            }
        }
    }
    DocumentLayout docLayout = new DocumentLayout(dlexString);
    LayoutData layoutData = new LayoutData(
        JsonConvert.DeserializeObject(
            jsonResult.ToString()
        ));
    Document document = docLayout.Layout(layoutData);
    document.Draw(outputPdf);
}

The example specifies the query's output as JSON using the for json auto, root('ProductsByCategory') clause, assigning ProductsByCategory as the root element and auto to allow the select statement to determine the JSON output format.

Refer to Format Query Results as JSON for more information.

The example then deserializes the JSON, loads it into a LayoutData instance, and uses the DocumentLayout instance and LayoutData instance to create the PDF document.

If using SQL Server, then the for json clause is an easy way to get the needed JSON while developing and testing your report. Save the JSON output as a file, upload it to your cloud storage space, and use the JSON to test your report in Designer.

Using Database Layout Data (SQL)

Let's now illustrate creating a PDF using results directly from querying the Northwinds database. Because the DLEX consists of a report and a subreport, we define a ReportDataRequired event handler to trigger an event when the DLEX requires layout data.

static void DatabaseVersionSql(String dlexString)
{
    string outputPdf = BASE_PATH + "subreport_db_sql_output.pdf";
    DocumentLayout documentLayout = new DocumentLayout(dlexString);
    documentLayout.ReportDataRequired += DocumentLayout_ReportDataRequired;
    LayoutData layoutData = new LayoutData();
    Document document = documentLayout.Layout(layoutData)
        document.Draw(outputPdf);
}

The ReportDataRequired event handler triggers an event and executes a callback function whenever a report or subreport element is parsed in a DLEX file. The callback function must have the same signature as the ReportDataRequired event's ReportDataRequiredEventHandler.

public delegate void ReportDataRequiredEventHandler(object sender, ReportDataRequiredEventArgs args);

The callback passes the sender and ReportDataRequiredEventArgs as parameters. The ReportDataRequiredEventArgs arguments consist of the DataProviderStack, ReportData, ElementId, and DataName.

A callback's implementation method is where the dynamic processing occurs that replaces the records in the DLEX template with data obtained from an SQL query.

private static void DocumentLayout_ReportDataRequired(object sender, ReportDataRequiredEventArgs args)
{
    if (args.ElementId == "ProductsByCategoryReport")
    {
        string sqlString = "SELECT CategoryID, CategoryName Name FROM Categories ";
        SqlConnection connection = new SqlConnection(CONNECTION_STRING);
        SqlCommand command = new SqlCommand(sqlString, connection);
        connection.Open();
        SqlDataReader reader = command.ExecuteReader();
        args.ReportData = new DataReaderReportData(connection, reader);
    }
    else if (args.ElementId == "ProductsByCategorySubReport")
    {
        string sqlString = "SELECT ProductID, ProductName, QuantityPerUnit, " 
            + "UnitPrice, Discontinued FROM Products WHERE CategoryID = " 
            + args.Data["CategoryID"] 
            + " ORDER BY ProductName ";
        SqlConnection connection = new SqlConnection(CONNECTION_STRING);
        SqlCommand command = new SqlCommand(sqlString, connection);
        connection.Open();
        SqlDataReader reader = command.ExecuteReader();
        args.ReportData = new DataReaderReportData(connection, reader);
    }
}

When fired, the event handler checks the id of the report and the subreport id and then requests the needed data. The subreport.dlex DLEX contains a Report element with the id ProductsByCategoryReport and a Subreport element with the id ProductsByCategorySubReport.

The record processing is straightforward. Each record from the SQL dataset gets replaced by a record element in the DLEX file. However, the event handler is fired twice. The first time fired, it processes the main report by querying the data source for category data. The second time fired, it processes the subreport product data. A complete PDF is created by applying the data from the two datasets to the DLEX template.

GitHub Project

Clone or view the example project at GitHub. This example code is contained in the LayoutEngineExample.cs file.

Clone or View Example Project on GitHub

Getting Started

Obtain the NuGet package to get started using DynamicPDF Core Suite. Login to DynamicPDF API to obtain a free account and start using DynamicPDF Designer Online.

NuGet Package

DynamicPDF Core Suite is available on NuGet and is part of the ceTe.DynamicPDF.CoreSuite.NET package. The easiest way to install the package is through the Visual Studio Package Manager. You can also download the package directly from NuGet.

NuGet Package ID: ceTe.DynamicPDF.CoreSuite.NET

DynamicPDF Core Suite Information

More information on DynamicPDF Core Suite can be found on its website.

DynamicPDF API

Use your existing DynamicPDF Core Suite username and password to login to DynamicPDF API and begin using Designer. If you do not have an account then you can a free account and begin using Designer.

Available on Other Platforms

DynamicPDF Core Suite is also available for the Java and COM/ActiveX platforms. Refer to the respective product pages for more details.

Why Choose DynamicPDF?

  • Transparent Pricing
  • Lots of Features
  • Easy to Use
  • Great Support
  • Efficient Performance
  • Product Maturity (Over 22 Years)
  • Free Evaluation
  • .NET Core Support (Most Products)
  • Flexible Licensing

We’re Not The Only Ones That Think We’re Great!