Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Is it possible to run in a Windows Container/App Service to convert HTML to PDFs? #238

Open
aligneddev opened this issue Mar 21, 2024 · 2 comments

Comments

@aligneddev
Copy link

aligneddev commented Mar 21, 2024

Rick Strahl has teased the idea of using WebView2 to create PDFs

I'd like to create an Azure App Service or hosted container to accept html and spit out PDFs.
Currently using itext7, but the HTML doesn't get rendered in the PDF the same and it's causing me a lot of grief.
Ideally, I could create HTML in Edge/Chrome and then send it to a PDF service and have them look exactly the same, using the same rendering engine (I'm looking at you WebView2) and I could host it in Linux, but that is an open issue on Azure and support 100s of requests a minute.

I've started but I have questions

  1. Is this possible?
  2. Are there licensing issues with this approach?
  3. How would I package and deploy this? Would a docker file/image work? Could you provide a pre-made image?
  4. what load could it handle, how big of a server would I need?
@aligneddev
Copy link
Author

aligneddev commented Mar 21, 2024

Here's what I have so far
using

using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.FileProviders;
using Microsoft.Web.WebView2.Core;
using Microsoft.Web.WebView2.WinForms;
using Microsoft.Web.WebView2.Wpf;
using System.IO;
using System.Text;
using System.Web;
using System.Windows;

namespace HtmlToPdf.Controllers
{
    [ApiController]
    [Route("[controller]")]
    public class PdfController : ControllerBase
    {
        [HttpPost("html")]
        public async Task<IActionResult> PostHtml(IList<IFormFile> files, [FromQuery] bool usePrintMediaType = false,
        bool useLandscapeOrientation = false)
        {
            var pdfFileName = $"{DateTimeOffset.UtcNow.Ticks}.pdf";
            if (files.Count == 1)
            {
                var pdf = await ConvertHtmlToPdfAsync(files.Single(), usePrintMediaType, useLandscapeOrientation);
                return File(pdf.OpenRead(), "application/pdf", pdfFileName);
            }
            else
            {
                return BadRequest();
            }
        }

        private async Task<FileInfo> ConvertHtmlToPdfAsync(IFormFile postedHtml, bool usePrintMediaType, bool useLandscapeOrientation)
        {
            await PrintToPdf(postedHtml, useLandscapeOrientation);
            return new FileInfo(postedHtml.FileName);
        }

        private async Task PrintToPdf(IFormFile postedHtml, bool useLandscapeOrientation)
        {
            var webView = new Microsoft.Web.WebView2.Wpf.WebView2
            {
                Source = new Uri("about:blank")
            };

            //// Initialize WebView2
            //await webView.EnsureCoreWebView2Async(null);
            //CoreWebView2PrintSettings printSettings = null;
            //if (useLandscapeOrientation)
            //{
            // can't find WebViewEnvironment
            //    printSettings = WebViewEnvironment.CreatePrintSettings();
            //    printSettings.Orientation =
            //        CoreWebView2PrintOrientation.Landscape;
            //}

            await webView.CoreWebView2.PrintToPdfAsync(
                postedHtml.FileName); //, printSettings);
        }

        public async Task<string> ReadAllText(IFormFile postedHtml)
        {
            byte[] buffer;
            using (var stream = postedHtml.OpenReadStream())
            {
                buffer = new byte[stream.Length];
                await stream.ReadAsync(buffer);
            }
            return Encoding.Default.GetString(buffer);
        }
    }
}

and I get a runtime error of
Exception thrown: 'System.InvalidOperationException' in PresentationCore.dll
Exception thrown: 'System.InvalidOperationException' in System.Private.CoreLib.dll
Exception thrown: 'System.InvalidOperationException' in System.Private.CoreLib.dll
Microsoft.AspNetCore.Diagnostics.DeveloperExceptionPageMiddleware: Error: An unhandled exception has occurred while executing the request.

System.InvalidOperationException: The calling thread must be STA, because many UI components require this.
at System.Windows.Input.InputManager..ctor()
at System.Windows.Input.InputManager.GetCurrentInputManagerImpl()
at System.Windows.Input.KeyboardNavigation..ctor()
at System.Windows.FrameworkElement.FrameworkServices..ctor()
at System.Windows.FrameworkElement.EnsureFrameworkServices()
at System.Windows.FrameworkElement..ctor()
at System.Windows.Interop.HwndHost..ctor()
at Microsoft.Web.WebView2.Wpf.WebView2..ctor()

@aligneddev
Copy link
Author

aligneddev commented Mar 27, 2024

Rick Strahl published a blog post
X post
"IAC, the bottom line is this component lets you print HTML to PDF in any Windows execution environment including inside services and IIS"

It'd be really great to run this in a Linux container

releated feedback

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant