4

I am facing a bit of an annoying situation. We try to use PuppeteerSharp in our application to generate background PDF, and while it works well in dev mode, it doesn't work when in production.

The app is a WebAPI 2.0 site, .NET4.7.1, Windows 10 machine. The main differences I would see beween the two environments are:

  • build in Release instead of Debug: calling my code from a console app either in Debug or Release mode seems to work in the same way
  • Hosting in IIS Express in development and full IIS in Production

We use the following code:

var launchOptions = new LaunchOptions
{
    DefaultViewport = new ViewPortOptions
    {
        Width = 1920,
        Height = 1080,
        IsLandscape = printOptions.Orientation == PrintOrientation.Landscape
    },
    ExecutablePath = this._chromiumPath,
    Timeout = Timeout,
    TransportFactory = AspNetWebSocketTransport.AspNetTransportFactory
};

var browser = await Puppeteer.LaunchAsync(launchOptions)
    .ConfigureAwait(false);

var page = await browser.NewPageAsync()
    .ConfigureAwait(false);
await page.EmulateMediaTypeAsync(PuppeteerSharp.Media.MediaType.Print)
    .ConfigureAwait(false);

await page.GoToAsync(url, Timeout, new[] { WaitUntilNavigation.Networkidle0 })
    .ConfigureAwait(false);
await page.WaitForTimeoutAsync(2000)
    .ConfigureAwait(false);
var options = new PdfOptions
{
    Width = printOptions.Format == PrintFormat.A4 ? "210mm" : "297mm",
    Height = printOptions.Format == PrintFormat.A4 ? "297mm" : "420mm",
    PrintBackground = true,
    Landscape = printOptions.Orientation == PrintOrientation.Landscape,
    MarginOptions = new PuppeteerSharp.Media.MarginOptions
    {
        Top = ".4in",
        Bottom = ".4in",
        Left = ".4in",
        Right = ".4in"
    }
};
await page.PdfAsync(outputFile, options)
    .ConfigureAwait(false);
return result;

page.GoToAsync never returns, and eventually times out.

Edit:

  • I set ConfigureAwait to false in all async calls
  • I tried using the AspNetWebSocketTransport.AspNetTransportFactory transport factory, which doesn't seem to work either
Hugues Stefanski
  • 1,172
  • 1
  • 7
  • 11

2 Answers2

2

If you are deploying your .NET Framework app on IIS. You need to also use PuppeteerSharp.AspNetFramwork and set the TransportFactory to the browser:

using (var browser = await Puppeteer.LaunchAsync(new LaunchOptions()
{
    Headless = true,
    TransportFactory = AspNetWebSocketTransport.AspNetTransportFactory,
    ExecutablePath = browserFetcher.GetExecutablePath(BrowserFetcher.DefaultRevision)
}).ConfigureAwait(false))

Update: the Nuget package is outdated (hard reference to PuppeteerSharp 1.0.0.0), but the source can be found here: https://github.com/hardkoded/puppeteer-sharp/blob/076897d0cf627c947c61a1192fcb20d968d05cbc/lib/PuppeteerSharp.AspNetFramework/AspNetWebSocketTransport.cs

thomasb
  • 5,816
  • 10
  • 57
  • 92
hardkoded
  • 18,915
  • 3
  • 52
  • 64
  • Aaah I see. I however do not have the static member `AspNetTransportFactory` available on the class `AspNetWebSocketTransport` after installing the package from nuget... – Hugues Stefanski Jun 17 '20 at 12:56
  • Give me till tomorrow, I will get you something. – hardkoded Jun 17 '20 at 13:07
  • 1
    @HuguesStefanski weird, the prop is there https://github.com/hardkoded/puppeteer-sharp/blob/caf4c15b9f8f909e9ebc37e94f968b146823c8c7/lib/PuppeteerSharp/LaunchOptions.cs#L146 – hardkoded Jun 17 '20 at 13:09
  • Sure, no rush, I'm glad you replied so fast already. I copied the class from github directly (I guess the `PuppeteerSharp.AspNetFramwork` nuget package did not publish the correct version). To be clearer, I get the options on the `LaunchOptions` object, but `AspNetWebSocketTransport` does not have a `AspNetTransportFactory`. But even with the code included it does not seem to work... I'll test it a bit further though – Hugues Stefanski Jun 17 '20 at 13:14
  • I'll also change the title, as the issue does not seem to be related to Debug/Release build configuration – Hugues Stefanski Jun 17 '20 at 13:15
  • Cool, give me till tomorrow :) – hardkoded Jun 17 '20 at 13:19
  • Same problem happens if calling from a Windows Service (not tested with the updated TransportFactory) – Hugues Stefanski Jun 17 '20 at 13:53
  • There is some conversations about that here https://github.com/puppeteer/puppeteer/issues/4290. That's even an issue on Puppeteer – hardkoded Jun 17 '20 at 14:06
  • Thanks for the info. I have some unit tests around pdf generation, which seem to work in CI (TeamCity). I am unsure if those are run in a console environment or not though. Also, the navigation seems to occur, as I can see data being read in my backend logs, but the process doesn't return somewhere between GoToPageAsync and return result. I'll keep investigating on my side as well – Hugues Stefanski Jun 17 '20 at 14:27
  • If you have some solid example, feel free to open an issue on the repo – hardkoded Jun 17 '20 at 15:55
  • I'll try doing that; as this is my job's solution, I can't share it as is... – Hugues Stefanski Jun 18 '20 at 06:41
  • Using my code in a small WebAPI new project, it seems to works allright, and my pdf gets printed (from IIS)... I'll keep investigating – Hugues Stefanski Jun 18 '20 at 08:07
  • As for the windows service, it was a chair/keyboard issue, as in I configured my shcedule wrong. I just received an automatically generated PDF via said WebService, so that part works at least. I'm starting to feel stupid :D – Hugues Stefanski Jun 18 '20 at 08:12
  • @HuguesStefanski I shipped PuppeteerSharp.AspNetFramework 2.0.3 you can play with that. If you have any issues feel free to create an issue on the repo – hardkoded Jun 18 '20 at 13:26
  • Hey, sorry for not replying. I am currently fighting our CI for other problems, I'll try this ASAP – Hugues Stefanski Jun 19 '20 at 12:02
  • 1
    Just tried the updated `AspNetFramework` version, still not working in IIS. I'll try keeping to either solve the problem or manage to reproduce in an isolated WebApi. I'll keep you informed. – Hugues Stefanski Jun 22 '20 at 08:43
  • 1
    Ok, I *might* have found the culprit: there is an open SignalR connection between the server and the client. I closed said connection (as is is useless in PDF rendering), and it seems that the GoToAsync method now returns properly with `NetworkIdle0`. My guess is that the browser considered that request as still active, and never returned. Why it works in debug mode or from another WebAPI remains a mystery, but I might be out of the mud (still to be checked on an actual server though...). Thanks for the support! – Hugues Stefanski Jun 22 '20 at 15:38
  • @hardkoded I'm having a similar issue. Can you spot anything amiss with my code?https://stackoverflow.com/questions/66171758/puppeteersharp-in-iis-asp-net-web-forms – DotNetDublin Feb 12 '21 at 12:22
2
using (var browser = await Puppeteer.LaunchAsync(new LaunchOptions()
{
    Headless = true,
    ExecutablePath = browserFetcher.GetExecutablePath(BrowserFetcher.DefaultRevision)
})

Helped me fix the issue, AspNetWebSocketTransport presents references issues and does not seem useful anymore

Sÿl
  • 585
  • 6
  • 8