📄 PlaywrightBrowserService.cs
using Microsoft.Extensions.Hosting;
using Microsoft.Playwright;

internal sealed class PlaywrightBrowserService : IHostedService, IAsyncDisposable
{
    private IPlaywright? _playwright;
    private IBrowser? _browser;

    public async Task StartAsync(CancellationToken cancellationToken)
    {
        _playwright = await Playwright.CreateAsync();
        _browser = await _playwright.Chromium.LaunchAsync(new BrowserTypeLaunchOptions { Headless = true });
    }

    public async Task StopAsync(CancellationToken cancellationToken) => await DisposeAsync();

    public Task<IPage> NewPageAsync() => _browser!.NewPageAsync();

    public async ValueTask DisposeAsync()
    {
        if (_browser is not null)
            await _browser.CloseAsync();
        _playwright?.Dispose();
    }
}