ASP.NET Core集成Playwright生成PDF时遇执行文件缺失及构建报错
问题场景
在ASP.NET Core中基于Playwright开发PDF生成服务,运行测试用例时出现Chromium执行文件缺失报错:
Executable doesn't exist at
C:\Users\wasys\AppData\Local\ms-playwright\chromium_headless_shell-1148\chrome-win\headless_shell.exe
尝试添加PostBuild脚本自动安装浏览器时,又出现构建报错:
Exception calling "ReadAllBytes" with "1" argument(s): "Could not find file
'D:\Temp\Solution.PdfGenerator\bin\Debug\net9.0\Microsoft.Playwright.dll'."
At D:\Temp\Solution.PdfGenerator\bin\Debug\net9.0\playwright.ps1:6 char:1
- [Reflection.Assembly]::Load([System.IO.File]::ReadAllBytes($playwrigh ...
+ CategoryInfo : NotSpecified: (:) [], MethodInvocationException + FullyQualifiedErrorId : FileNotFoundExceptionUnable to find type [Microsoft.Playwright.Program].
At D:\Temp\Solution.PdfGenerator\bin\Debug\net9.0\playwright.ps1:7 char:6
- exit [Microsoft.Playwright.Program]::Main($args)
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
- CategoryInfo : InvalidOperation: (Microsoft.Playwright.Program:TypeName) [], RuntimeException
- FullyQualifiedErrorId : TypeNotFound
PDF生成服务代码
public class PdfgeneratorService(IServiceProvider serviceProvider, ILoggerFactory loggerFactory) : IPdfgeneratorService { public async Task GeneratePdf<[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.All)] TComponent> (string fileName, Dictionary<string, object?> htmlData) where TComponent : IComponent { await using var htmlRenderer = new HtmlRenderer(serviceProvider, loggerFactory); var html = await htmlRenderer.Dispatcher.InvokeAsync(async () => { var parameters = ParameterView.FromDictionary(htmlData); var output = await htmlRenderer.RenderComponentAsync(typeof(TComponent), parameters); return output.ToHtmlString(); }); using var playwright = await Playwright.CreateAsync(); //ERROR IS APPEARING IN THIS LINE var browser = await playwright.Chromium.LaunchAsync(new BrowserTypeLaunchOptions { Headless = true }); var page = await browser.NewPageAsync(); await page.SetContentAsync(html); await page.PdfAsync(new PagePdfOptions { Format = "A4", Path = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.DesktopDirectory), $"{fileName.Replace(".pdf","")}.pdf") }); await page.CloseAsync(); } }
测试代码
public class PdfgeneratorServiceTests { private PdfgeneratorServiceTestBuilder builder; public PdfgeneratorServiceTests() { this.builder = new PdfgeneratorServiceTestBuilder(); } [Fact] public async Task GeneratePdf_Success() { var invoice = InvoiceGenerator.Generate(); var htmlDictionary = new Dictionary<string, object?> { { "Invoice", invoice } }; var exception = await Record.ExceptionAsync(async () => await builder.PdfgeneratorService.GeneratePdf<InvoiceView>("Test", htmlDictionary) ); Assert.Null(exception); } }
尝试的PostBuild脚本
<Target Name="PostBuild" AfterTargets="PostBuildEvent"> <Exec Command="powershell.exe -Command $(TargetDir)playwright.ps1 install chrome;" /> </Target>
解决方案
1. 替换PostBuild脚本,使用Playwright CLI安装浏览器
放弃依赖本地playwright.ps1的方式,直接通过dotnet工具调用Playwright CLI,避免dll路径依赖问题:
<Target Name="PostBuild" AfterTargets="PostBuildEvent"> <Exec Command="dotnet tool run playwright install chromium" /> </Target>
如果尚未安装Playwright CLI工具,先执行全局安装命令:
dotnet tool install --global Microsoft.Playwright.CLI
2. 手动触发浏览器安装(应急方案)
如果构建脚本仍无法正常执行,可在项目根目录下手动运行以下命令,强制下载Chromium:
dotnet tool run playwright install chromium
3. 代码中手动指定浏览器路径(可选)
若浏览器安装路径存在异常,可在LaunchAsync时显式指定Chromium的执行文件路径(替换XXXX为实际版本号):
var browser = await playwright.Chromium.LaunchAsync(new BrowserTypeLaunchOptions { Headless = true, ExecutablePath = @"C:\Users\wasys\AppData\Local\ms-playwright\chromium-XXXX\chrome-win\chrome.exe" });
4. 确保测试项目依赖完整
在测试项目中同样安装Microsoft.Playwright NuGet包,或在测试初始化逻辑中添加一次浏览器安装检查,避免测试运行时缺失依赖。
内容的提问来源于stack exchange,提问作者Wasyster

