Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles
(untagged)

Create PDF from HTML using C#, Nustache, Mustache and Pechkin

0.00/5 (No votes)
5 Mar 2016 7  
This article explains how to create a PDF file using C# object

Background

Recently, I had to work on a task where we needed to create a PDF version of a Silverlight page.The data to the markup (XAML) was from a C# object (yes, you guessed it! we used MVVM pattern) and we wanted to use that object for the PDF file. Below are the components we used to create a PDF file.

Dependencies

As mentioned above, you need:

  • Nustache library
  • Pechkin

I have excluded these DLLs in the sample code because one of the DLLs, wkhtmltox0, of Pechkin package is about 29 MB resulting the attachment bigger. So, you will get build error if you just open and hit F5 (The source code can be opened in either VS 2010 or VS 2012).

Installing Dependencies

Using Nuget Package Manager

Manual Installation

You can also download the .zip version of these and manually add reference to your project. In this case, you should do the following settings in order to make the code work.

Add reference:

Add these files to the root of the project and set 'copy if newer':

Update web.config (or App.config in case you use it in Console):

<runtime>
    <assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
      <dependentAssembly>
        <assemblyIdentity name="Common.Logging" 
        publicKeyToken="af08829b84f0328e" culture="neutral" />
        <bindingRedirect oldVersion="0.0.0.0-2.1.2.0" newVersion="2.1.2.0" />
      </dependentAssembly>
    </assemblyBinding>
  </runtime>

Using the Code

The sample solution has three projects:

  1. WCF service
  2. Silverlight app
  3. Web app

PDFService

The class PdfService offers two methods:

  • PdfBytes - Accepts any string content and converts as PDF bytes to the client.
  • EmployeePdf - Specific to Employee object and it converts the employee data into an html string which can then be passed to the PdfBytes method to get PDF bytes.
public class PdfService : IPdfService
{
    public PdfResult PdfBytes(string content)
    {
        var result = new PdfResult();
        try
        {
            var oc = new ObjectConfig();
            oc.SetPrintBackground(true); //to apply the background colors in the pdf
            var footer = oc.Footer;
            footer.SetFontSize(8);
            footer.SetTexts("For internal use only", string.Empty, string.Empty);
            result.Bytes = new SynchronizedPechkin(new GlobalConfig()).Convert(oc, content);
        }
        catch (Exception ex)
        {
            result.Error = ex.Message;
        }
        return result;
    }

    public PdfResult EmployeePdf(Employee employee)
    {
        string nustachTemplate = Path.Combine
    (HostingEnvironment.ApplicationPhysicalPath, "App_Data", "EmployeeTemplate.html");
        var employeeHtml = Render.FileToString(nustachTemplate, employee);
        return PdfBytes(employeeHtml);
    }
}

The Employee object's data are injected into the Mustache html template. You can apply styles (only inline styles, style sheets cannot be linked) to design the page output.

<html>
<head>
    <title>Employee Print</title>
    <style>
        body {
            margin: 5px;
        }
 
        h3 {
            text-align: center;
            border-radius: 10px;
        }
 
        h4 {
            background: silver;
            border-radius: 5px;
            padding-left: 10px;
        }
    </style>
</head>
<body>
 
    <h3>Employee {{Name}}</h3>
    <h4>Basic Details</h4>
    <div>
        <p>Name:</p>
        <p>{{Name}}</p>
    </div>
    <div>
        <p>Email:</p>
        <p>{{Email}}</p>
    </div>
    <div>
        <p>Address:</p>
        <p>{{Address}}</p>
    </div>
    <h4>Skills</h4>
 
    {{#Skills}}
  <p>{{Name}}</p>
    {{/Skills}}
    
    {{^Skills}}
  <p>No skills</p>
    {{/Skills}}
    <h4>Hobbies</h4>
 
    {{#Hobbies}}
  <p>{{Name}}</p>
    {{/Hobbies}}
 
      {{^Hobbies}}
  <p>No hobbies</p>
    {{/Hobbies}}
 
     <h4>Jobs</h4>
    {{#Jobs}}
  <p>{{Company}}: as a {{Role}} for {{NoOfYears}} years.</p>
    {{/Jobs}}
 
    {{^Jobs}}
  <p>No jobs</p>
    {{/Jobs}}
</body>
</html>

And the Employee class:

[DataContract]
public class Employee
{
    public Employee()
    {
        Hobbies = new List<Hobby>();
        Skills = new List<Skill>();
        Jobs = new List<Job>();
    }

    [DataMember]
    public string Name { get; set; }
    [DataMember]
    public string Address { get; set; }
    [DataMember]
    public string Email { get; set; }
    [DataMember]
    public List<Hobby> Hobbies { get; set; }
    [DataMember]
    public List<Skill> Skills { get; set; }
    [DataMember]
    public List<Job> Jobs { get; set; }
}

Here is the final PDF:

SilverlightApplication1

A client application using the PDFService to generate Pdf. The code to call the service and save the file.

private void ButtonBase_OnClick(object sender, RoutedEventArgs e)
{
    var dialog = new SaveFileDialog()
        {
            DefaultExt = "Adobe PDF Files(*.pdf)",
            Filter = "PDF (*.PDF)|*.PDF",
            FilterIndex = 2
        };

    if (dialog.ShowDialog() == true)
    {
        var client = new PdfServiceClient();
        var emp = GetEmployee();
        client.EmployeePdfCompleted += (s, ea) =>
        {
            if (ea.Error != null)
            {
                MessageBox.Show(string.Format("Error:{0}", ea.Error.Message));
                return;
            }
            if (!string.IsNullOrWhiteSpace(ea.Result.Error))
            {
                MessageBox.Show(string.Format("Error:{0}", ea.Result.Error));
                return;
            }
            using (System.IO.Stream stream = dialog.OpenFile())
            {
                stream.Write(ea.Result.Bytes, 0, ea.Result.Bytes.Length);

            }
            MessageBox.Show("Pdf saved");
        };
        client.EmployeePdfAsync(emp);
    }
}

Pros and Cons

Pros

  • Easy to build page content
  • We can CSS to style the output
  • No manual calculation of page count in PDF. Pages generated automatically based on the content
  • Free libraries

Cons

  • DLLs are big in size
  • From Quake2Player: (I have not experienced this, but thank you for the information)

    One important cons is that some hostings prevent the execution of DLLs through kernel. For example, Azure Websites. So it is not possible to execute wkhtmltopdf.exe, for example.

  • Any other you may think of?

Points of Interest

The Nustache and Mustache template are not really a requirement for creating a PDF file. You can create without it just by passing a string or build your own html as far as it meets the requirement. I personally prefer Mustache as it is easy to build html, more importantly you can show or hide elements based on conditions while you have the full layout designed in HTML.

Before You Download the Sample Code

Again, the sample code will not work unless you follow the instructions mentioned in the Dependencies section at the top.

History

  • First version

Finally...

I wanted to share my work on creating PDF and I did now. If somebody finds this interesting and it can be of help, then I will feel it is worth the effort. As always, comments/suggestions are welcome.

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here