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