Click here to Skip to main content
15,885,278 members
Articles / Web Development / HTML

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

Rate me:
Please Sign up or sign in to vote.
4.87/5 (24 votes)
5 Mar 2016CPOL3 min read 67.2K   1.5K   47   9
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

Image 1

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:

Image 2

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

Image 3

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

XML
<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

Image 4

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

C#
[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:

Image 5

SilverlightApplication1

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

C#
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, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
Architect CGI
India India
This member has not yet provided a Biography. Assume it's interesting and varied, and probably something to do with programming.

Comments and Discussions

 
QuestionGood information for PDF creation Pin
Tridip Bhattacharjee3-Apr-17 22:37
professionalTridip Bhattacharjee3-Apr-17 22:37 
QuestionProblems with special characters (german unmlauts) in footer Pin
susad1-Feb-16 23:34
susad1-Feb-16 23:34 
AnswerRe: Problems with special characters (german unmlauts) in footer Pin
Prabu ram1-Mar-16 17:09
Prabu ram1-Mar-16 17:09 
PraiseMy vote of 5 Pin
susad7-Jan-16 2:26
susad7-Jan-16 2:26 
GeneralMy vote of 2 Pin
silvia.stanila29-Oct-14 20:05
silvia.stanila29-Oct-14 20:05 
Question"Cons: Any other you may think of?" Pin
Quake2Player9-Dec-13 10:49
Quake2Player9-Dec-13 10:49 
AnswerRe: "Cons: Any other you may think of?" Pin
Prabu ram9-Dec-13 17:37
Prabu ram9-Dec-13 17:37 
GeneralRe: "Cons: Any other you may think of?" Pin
Beatrice Monk2-Nov-14 22:57
professionalBeatrice Monk2-Nov-14 22:57 

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.