I have the following (rather simplified) code:
public class Service
{
private IPage? _page;
private readonly ScreenshotOptions _options;
public Service(IOptions<ScreenshotOptions> options) => _options = options.Value;
public async Task CreateScreenshotAsync()
{
if (_page == null)
_page = await InitializePlaywrightAsync();
await _page.ScreenshotAsync(new PageScreenshotOptions { Path = _options.Filename });
// all the other stuff
}
private async Task<IPage> InitializePlaywrightAsync()
{
var playwright = await Playwright.CreateAsync();
var browser = await playwright.Chromium.LaunchAsync();
var page = await browser.NewPageAsync();
await page.SetViewportSizeAsync(_options.Width, _options.Height);
return page;
}
}
// Program.cs
builder.Services.AddSingleton<Service>();
I'd prefer to have InitializePlaywrightAsync() not inside Service but let the ASP.NET Core DI container do the work of instantiating IPage. Unfortunately, the following code does not compile:
public class Service
{
private IPage _page;
private readonly ScreenshotOptions _options;
public Service(IOptions<ScreenshotOptions> options, IPage page)
{
_options = options.Value;
_page = page;
}
public async Task CreateScreenshotAsync()
{
await _page.ScreenshotAsync(new PageScreenshotOptions { Path = _options.Filename });
// all the other stuff
}
}
// Program.cs - compilation error
builder.Services.AddSingleton<IPage>((IOptions<ScreenshotOptions> options) =>
{
var playwright = await Playwright.CreateAsync();
var browser = await playwright.Chromium.LaunchAsync();
var page = await browser.NewPageAsync();
await page.SetViewportSizeAsync(options.Width, options.Height);
return page;
});
builder.Services.AddSingleton<Service>();
Using a dedicated factory class also is not super nice as the DI container does not accept an asynchronous delegate:
public class PageFactory
{
private readonly ScreenshotOptions _options;
public PageFactory(IOptions<ScreenshotOptions> options) => _options = options.Value;
public async Task<IPage> InitializePlaywrightAsync()
{
var playwright = await Playwright.CreateAsync();
var browser = await playwright.Chromium.LaunchAsync();
var page = await browser.NewPageAsync();
await page.SetViewportSizeAsync(_options.Width, _options.Height);
return page;
}
}
// Program.cs - compilation error
builder.Services.AddSingleton<IPage>(async provider => await provider.GetRequiredService<PageFactory>().InitializePlaywrightAsync());
I'm curious whether there is any elegant way of moving the InitializePlaywrightAsync() logic into the DI container.