Alex
Alex

Reputation: 937

Phantom pdf on Azure in ASP.NET Core

I am using jsreport and the phantom pdf recipe to render a View as a pdf in ASP.NET Core. The project is running in Azure as an App Service. This works fine on my local machine, but when I publish to Azure, I get the below error message.

Exception: Call to Node module failed with error: ReferenceError: e is not defined at module.exports (D:\home\site\wwwroot\serviceCallDetailsPdf.js:18:26)

Here is my js file that is in the root of my project (same directory level as wwwroot, Views, Controllers, etc).

module.exports = function (callback, html, htmlFooter) {
    var jsreport = require('jsreport-core')();

    jsreport.init().then(function () {
        return jsreport.render({
            template: {
                content: html,
                engine: 'jsrender',
                recipe: 'phantom-pdf',
                phantom: {
                    orientation: "landscape",
                    allowLocalFilesAccess: true,
                    footer: htmlFooter
                }
            }
        }).then(function (resp) {
            callback(/* error */ null, resp.content.toString());
        });
    }).catch(function (e) {
        callback(/* error */ e, null);
    });

    callback(/* error */ e, null);
};

Note: The very last call back usually would not be there. If I remove it, the error I get changes to the Node.js module timing out after 60000 milliseconds and of course it takes 60 seconds for it to display.

I had to update my project.json file to include *.js and node_modules in publishOptions otherwise I would get an error saying Node.js could not fine the file I am calling. I know this is not the proper way to do this (should use Gulp to copy only what I need, but I just want to get it working first).

I've added services.AddNodeServices(); to ConfigureServices and also "Microsoft.AspNetCore.NodeServices": "1.1.0" to project.json.

Here is my package.json file that was auto-generated:

{
  "name": "projectname",
  "version": "1.0.0",
  "description": "",
  "main": "serviceCallDetailsPdf.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  "author": "",
  "license": "ISC",
  "dependencies": {
    "jsreport-core":"1.1.1",
    "jsreport-jsrender": "1.0.1",
    "jsreport-phantom-pdf": "1.3.1"
  }
}

Finally, here is my Action:

[HttpGet]
public async Task<IActionResult> ServiceCallDetailsToPdf(int id)
{
    var call = _repository.PullCallDetails(id, User.Identity.RegionId(), User.Identity.TimeZoneOffsetId());

    // Render view as string
    var html = await _viewRenderService.RenderToStringAsync("Render/ServiceCallDetailsPdf", call);
    html = html.Replace("<style></style>", @"<style>@font-face{font-family:'Open Sans';src:url({#asset OpenSans-Regular.ttf @encoding=dataURI});format('ttf');}*{font-family:'Open Sans';}h2{font-weight:300;line-height:1.1;}</style>");

    var htmlFooter = "<style>*{font-family:'Open Sans';text-align:center;}</style>" + "Page {#pageNum} of {#numPages}";

    // Invoke node job to create the pdf
    var result = await _nodeServices.InvokeAsync<byte[]>("./serviceCallDetailsPdf", html, htmlFooter);

    // Content disposition 'inline' will return the pdf to the browser and not download it
    var contentDisposition = new ContentDispositionHeaderValue("inline");
    // Add file name to content disposition so if it is downloaded, it uses the correct file name
    contentDisposition.SetHttpFileName("dispatch" + id.ToString() + ".pdf");
    Response.Headers[HeaderNames.ContentDisposition] = contentDisposition.ToString();

    return File(result, "application/pdf");
}

Is it possible to debug the javascript file that is being called? I've spent a few days and numerous hours trying to figure out why this won't work. Any help would be greatly appreciated.


Update

I believe I found my answer from these links:

https://github.com/projectkudu/kudu/wiki/Azure-Web-App-sandbox

PhantomJS as web job in Azure

This basically means you cannot use the phantom pdf recipe in an Azure App Service. Can anyone else confirm? If this is the case, does anyone know of a html to pdf renderer that will work in an Azure App Service?

Upvotes: 1

Views: 1971

Answers (1)

Jan Blaha
Jan Blaha

Reputation: 3095

phantomjs and other pdf rendering won't work in Azure App service running on default Windows Server. However you can now use Azure App service running on linux where jsreport nicely works.

You just need to switch to Web App on Linux when creating new App Service and use node based container. Then you can use docker hub to download an image with jsreport right into the Web App. The simplest is to use official jsreport image but it is easy to use also your own.

Links
Tutorial how run jsreport on Azure Web App on linux
jsreport official docker image

I'm aware I didn't answer how to actually run it in the same app as asp.net core. I don't know how to do that currently, but I suggest you to run asp.net application and jsreport in separate apps. You can easily invoke jsreport rendering through REST. This could also improve your architecture design.

Upvotes: 1

Related Questions