Wednesday, June 6, 2018

Converting HTML to PDF in .Net Core

A couple of weeks ago I wrote a post about merging multiple PDFs together. Once we got that piece up and running we decided we wanted to create a PDF on the fly from some markup. Once again I turned to Google to find a way.

This turned out to be one of the greatest discoveries I could have possibly made about .Net Core 2.0: you can use node.js from right inside! It's even really easy!

First, if you're not referencing the default NuGet package of Microsoft.AspNetCore.All then you'll want to install Microsoft.AspNetCore.NodeServices.

Once you have the package installed you need to add node services to your configuration. Just add this to your ConfigureService method of Startup.cs:
services.AddNodeServices();

The next part seems a bit counter-intuitive to me, but it's what we have to do: change your controller method that is going to invoke node.js so that it accepts a parameter of type INodeServices using the FromServices attribute. So if my old controller method signature was this:
public async Task<IActionResult> GeneratePdf()
it would look like this after my changes:
public async Task<IActionResult> GeneratePdf([FromServices] INodeServices nodeServices)

Now we're free to invoke node.js functions from inside this controller method. When we're ready to invoke a node.js function we simply call InvokeAsync on our nodeServices parameter and pass in the location of the node.js function file and whatever parameters we are passing to the function.
var pdf = await nodeServices.InvokeAsync<byte[]>("./create-pdf", html);

In my particular case I'm passing in the markup I want to convert to a PDF. The node function is in a file at the root of my project structure (it's a sibling of Startup.cs) named "create-pdf.js".
So that's how you get it all setup, and this is how you actually use node.js to convert markup to a PDF:
   1:  module.exports = function (callback, html) {
   2:    var jsreport = require('jsreport-core')();
   3:  
   4:    jsreport.init().then(function () {
   5:      return jsreport.render({
   6:        template: {
   7:          content: html,
   8:          engine: 'jsrender',
   9:          recipe: 'phantom-pdf',
  10:          phantom: {
  11:            format: 'Letter'
  12:          }
  13:        }
  14:      }).then(function (resp) {
  15:        callback(/* error */ null, resp.content.toJSON().data);
  16:      });
  17:    }).catch(function (e) {
  18:      callback(/* error */ e, null);
  19:    });
  20:  };

This approach uses jsreport-core to generate the PDF from the provided markup, then provides the byte array representing the PDF back to the caller (my controller method). From there I can do what I want with the PDF.

1 comment:

  1. Hello Andrew,
    Thank you for sharing this post. ZetPDF is a .net SDK for adding PDF render and print support in .net applications. It is designed to solve most developer’s needs with regards to PDF rendering. It is Written entirely in C#, it is a 100% .NET component, not just a COM wrapper. They are best at what they are providing.

    ReplyDelete