[]
The following walkthrough takes you through a step-by-step process on how to render a PDF report using Render HTML to PDF feature.
Consider a scenario where a PDF report is to be generated regarding the products available in a supermarket. These products have been grouped into different categories like beverages, condiments, dairy products, seafood etc. The unit price and stock of each product as well as the whole category is also maintained in separate columns.
The PDF report is generated by using a sample database for the data of products and an HTML template file which outlines the UI of the final PDF report.
Suppose we have the following pre-requisites available using which we will render a PDF report:
Data source to provide data for the report. Here, we are using 'GcNWind.xml' which contains the schema and required data.
HTML template file which defines the layout of the final report to be created. Here, we are using 'ProductListTemplate.html' which uses {{Mustache}} syntax to specify data bound fields.
Stubble.core package which is available on Nuget and is used to bind data to template.
HTML template file
html * {
font-family: 'Trebuchet MS', Arial, Helvetica, sans-serif !important;
}
h1 {
color: #1a5276;
background-color: #d2b4de;
text-align: center;
padding: 6px;
}
thead {
display: table-header-group;
}
#products {
font-family: 'Trebuchet MS', Arial, Helvetica, sans-serif;
border-collapse: collapse;
width: 100%;
}
#products td, #products th {
border: 1px solid #ddd;
padding: 8px;
}
#products tr:nth-child(even) {
background-color: #f2f2f2;
}
#products tr:hover {
background-color: #ddd;
}
#products th {
padding-top: 12px;
padding-bottom: 12px;
text-align: left;
background-color: #a569bd;
color: white;
}
span{
float:right;
}
Products Stock Report
{{#Query}}
{{#ProductList}}
{{/ProductList}}
{{/Query}}
Description
Unit Price
Quantity Per Unit
{{CategoryName}} Total Units in Stock: {{CategoryStockTotal}}
{{ProductName}}
{{UnitPrice}}
{{UnitsInStock}}
The below image shows the output of HTML template file:
Create a .NET Core console application in Visual Studio and install 'Grapecity.Documents.Pdf' package from nuget by following the steps metioned in 'Getting Started'.
Create a class file with name 'ProductListTemplate' and define a method 'CreatePdf' which would be used to convert the HTML to PDF report.
Load the datasource XML file "GcNWind.xml" using DataSet class and read its XML schema using ReadXML method of DataSet class.
Fetch the DataTable "CategoriesAndProducts" from the DataSet using DataTable class. Cast the XML data of datasource into a list and use a LINQ query to create grouped data from the data table.
using System;
using System.IO;
using System.Drawing;
using System.Collections.Generic;
using System.Data;
using System.Linq;
using System.Reflection;
using GrapeCity.Documents.Pdf;
using GrapeCity.Documents.Html;
using Newtonsoft.Json;
using System.Text.RegularExpressions;
using GcPdfWeb.Samples.Common;
public class ProductListTemplate
{
public void CreatePDF(Stream stream)
{
using (var ds = new DataSet())
{
//Fetch data
ds.ReadXml(Path.Combine("Resources", "data", "GcNWind.xml"));
DataTable dtCPts = ds.Tables["CategoriesAndProducts"];
var categoryProducts =
from prod in dtCPts.Select()
group prod by prod["CategoryName"] into newGroup
select newGroup;
//Create grouped data, to display the product list based on Category groups
//and calculate the total units in stock for each category
List lstCategory = new List();
foreach (var nameGroup in categoryProducts)
{
List lstProduct = new List();
int TotalCategoryStock = 0;
foreach (var pro in nameGroup)
{
lstProduct.Add(new
{
ProductName = pro["ProductName"].ToString(),
UnitsInStock = pro["UnitsInStock"].ToString(),
UnitPrice = pro["UnitPrice"].ToString()
});
TotalCategoryStock += Convert.ToInt32(pro["UnitsInStock"]);
}
lstCategory.Add(new
{
CategoryName = nameGroup.Key.ToString(),
CategoryStockTotal = TotalCategoryStock,
ProductList = lstProduct
});
}
var dataBound = new { Query = lstCategory };
Load the HTML template 'ProductListTemplate.html' using ReadAllText method of File class which reads the template file.
Bind the template to datasource using the Render method of StubbleBuilder class (from the StubbleBuilder library).
var template = File.ReadAllText(Path.Combine("Resources", "Misc", "ProductListTemplate.html"));
//Bind the template to data
var builder = new Stubble.Core.Builders.StubbleBuilder();
var boundTemplate = builder.Build().Render(template, dataBound);
Create an instance of GcHtmlBrowser class that is used to render HTML.
To render the bound HTML, pass the data bound template as a parameter to the NewPage method of the browser.
Define PDF options such as header and footer, for rendering HTML to PDF using the PdfOptions class.
Render the generated HTML to a temporary file by using GetTempFileName method of the Path class.
Create a PDF file from the rendered temporary file by using the SaveAsPdf method.
// Create an instance of GcHtmlBrowser that is used to render HTML:
using var browser = Util.NewHtmlBrowser();
// Render the bound HTML:
using var htmlPage = browser.NewPage(boundTemplate);
// PdfOptions specifies options for HTML to PDF conversion:
var pdfOptions = new PdfOptions()
{
Margins = new PdfMargins(0.2f, 1, 0.2f, 1),
PreferCSSPageSize = false,
DisplayHeaderFooter = true,
HeaderTemplate = "" +
"Product Price List" +
"Page of " +
"",
FooterTemplate = "" +
"(c) GrapeCity, Inc. All Rights Reserved." +
"Generated on "
};
// Render the generated HTML to the temporary file:
var tmp = Path.GetTempFileName();
htmlPage.SaveAsPdf(tmp, pdfOptions);
// Copy the created PDF from the temp file to target stream:
using (var ts = File.OpenRead(tmp))
ts.CopyTo(stream);
// Clean up:
File.Delete(tmp);
}
Invoke 'CreatePdf' method to save the PDF report.
static void Main(string[] args)
{
var fname = "ProductListTemplate.pdf";
Console.WriteLine($"Press ENTER to create '{fname}' in the current directory,\nor enter an alternative file name:");
var t = Console.ReadLine();
if (!string.IsNullOrWhiteSpace(t))
fname = t;
fname = Path.GetFullPath(fname);
Console.WriteLine($"Generating '{fname}'...");
var sample = new ProductListTemplate();
using (FileStream fs = new FileStream(fname, FileMode.Create))
{
sample.CreatePDF(fs);
Console.WriteLine($"Created '{fname}' successfully.");
}
Console.WriteLine("Press any key to exit...");
Console.ReadKey();
}
The final PDF report is a multi-page report, one of whose pages is displayed below: