MicrosoftEdge/WebView2Feedback

[Problem/Bug]: WebView DevTools PrintToPdf hangs in Server Environment, while WebView.PrintToPdfStreamAsync() works

RickStrahl opened this issue · 0 comments

What happened?

I've recently re-written my HTML to PDF conversion library Westwind.WebView to use the Page.printToPdf DevTools functionality rather than WebVIew.PrintToPdfStreamAsync().

It took a bit of work to make the non-interactive use case work originally by manufacturing an internal STA thread and setting up the right synchronization context. I bring this up because that's a question that's come up a lot in questions here and the library demonstrates how to get the WebView to run in a unattended and low rights server environment.

It's been working with the original WebView.PrintToPdfStreamAsync() but when I changed over to the the DevTools protocols PDF export the code hangs on this WebView.CallDevToolsProtocolMethodAsync() call in a server environment (in IIS):

var pdfBase64 = await WebView.CallDevToolsProtocolMethodAsync("Page.printToPDF", json);

The request hangs at that point and never returns in a server environment.

The same code works in a non-server environment - it works in a Console app, it works in standalone Kestrel, and it works in Windows desktop apps (all of which have some sort of desktop functionality).

As mentioned the original code works in the exact same call context.

 using var stream = await WebView.PrintToPdfStreamAsync(parms);

The only difference between these two calls is these two code blocks - the rest of the code that sets up the thread environment and synchronization context is identical (you can check out the Westwind.WebView library and use the AspNetSample to test this if so inclined).

The code that works using WebView.PrintToPdfStreamAsync():

 try
 {
     var parms = GetWebViewPrintSettings();

     // HACK: Remove!
     StringUtils.LogString("About to Printing DevTools");

     // we have to turn the stream into something physical because the form won't stay alive
     using var stream = await WebView.PrintToPdfStreamAsync(parms);

     //    // HACK: Remove!
     StringUtils.LogString("Completed Printing");

     var ms = new MemoryStream();
     await stream.CopyToAsync(ms);
     ms.Position = 0;

     ResultStream = ms;  // don't Close()/Dispose()!
     IsSuccess = true;
     return ResultStream;
 }

The code that doesn't work using the DevTools printToPdf functionality instead:

try
{
    var json = GetDevToolsWebViewPrintSettingsJson();
    Console.WriteLine(json);
    // HACK: Remove!
    StringUtils.LogString("About to Printing DevTools");

    var pdfBase64 = await WebView.CallDevToolsProtocolMethodAsync("Page.printToPDF", json);

    // HACK: Remove!
    StringUtils.LogString("Completed Printing DevTools");

    if (!string.IsNullOrEmpty(pdfBase64))
    {
        // avoid JSON Serializer Dependency
        var b64Data = StringUtils.ExtractString(pdfBase64, "\"data\":\"", "\"}");
        var pdfData = Convert.FromBase64String(b64Data);

        var ms = new MemoryStream(pdfData);
        ResultStream = ms;
        IsSuccess = true;
        return ResultStream;
    }

    IsSuccess = false;
    LastException = new InvalidOperationException("No PDF output was generated.");
    return null;
}

As mentioned I have a front end library that tests this from inside of an ASP.NET application hosted inside of IIS using an ApplicationPoolIdentity hosted ApplicationPool. It works for the WebView call and it fails with the DevTools call.

The question is:

  • Why is there a difference? The environment is exactly identical and since it works for the WebView call, we know that the permissions and environment are set up correctly.
  • Are there any additional requirements for permissions required for using DevTools functions that don't exist for the WebView function?
  • If so is that something that can be fixed

FWIW, I'm using the DevTools version over the plain WebView version as there are additional features that are not supported by the plain WebView version specifically creation of Table of Contents and recognizing more print options that are ignored by the Webview version.

I know this should be possible because a number of other 'headless automation tools' (not using WebView2 specifically) are using these same DevTools functions so Chromium seems to support this. Somehow the environment is treated differently for the WebView call vs DevTools call.

.NET 9.0.0 • x64
Microsoft Windows 10.0.22631 (en-US)
WebView Runtime: 131.0.2903.70
WebView Sdk: 1.0.2903.40

Importance

Blocking. My app's basic functions are not working due to this issue.

Runtime Channel

Stable release (WebView2 Runtime)

Runtime Version

131.0.2903.70

SDK Version

1.0.2903.40

Framework

Other

Operating System

Windows 11

OS Version

10.0.22631

Repro steps

Clone Westwind.WebView project from:

https://github.com/RickStrahl/WestWind.WebView

Run the AspNetSample project.

Create an IIS WebSite or Application

Map it to the output folder from ./publish.cmd (../WebApp folder)

Set the Application Pool to ApplicationPoolIdentity (default)

Run http://localhost:2022/pdf/raw

You'll see the app hang and never return.

Change the code here:

https://github.com/RickStrahl/Westwind.WebView/blob/7f189719c42acf716294e8dc741234145ea3dc49/Westwind.WebView/HtmlToPdf/CoreWebViewHeadlessHost.cs#L264

Uncomment the try {} block and comment the current try {} block.

Run ./publish again

Run http://localhost:2022/pdf/raw

Should work now.

Repros in Edge Browser

No, issue does not reproduce in the corresponding Edge version

Regression

No, this never worked

Last working version (if regression)

No response