microsoft / playwright-dotnet

.NET version of the Playwright testing and automation library.
https://playwright.dev/dotnet/
MIT License
2.48k stars 237 forks source link

[BUG] Azure Function Setup Issue: System.Text.Json version issue #2696

Closed weightmans-seanbrogan closed 1 year ago

weightmans-seanbrogan commented 1 year ago

System info

Description

I'm trying to get playwright browsers installed locally within an azure function underneath the .playwright/packages/.local_browsers directory so that an azure function can be self contained within a cloud hosted azure function. The below provided code is a separate example i have created from the main project that replicates the issue i am having. I have tried multiple approaches to do this using environment variables but none have seemed to work except for one.

The only time I have managed to get it to work is when:

Source code

using System;
using System.IO;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.Azure.WebJobs;
using Microsoft.Azure.WebJobs.Host;
using Microsoft.Extensions.Logging;
using Microsoft.Playwright;

namespace Azure.Playwright.Function
{
    public class Function1
    {
        [FunctionName("Function1")]
        public async Task RunAsync([TimerTrigger("0 */1 * * * *")] TimerInfo myTimer, ILogger log)
        {
            var browserPath = Path.Combine(Directory.GetCurrentDirectory(), ".playwright", "package", ".local_browsers");

            Environment.SetEnvironmentVariable("HOME_EXPANDED", browserPath);
            Environment.SetEnvironmentVariable("PLAYWRIGHT_BROWSERS_PATH", Environment.GetEnvironmentVariable("HOME_EXPANDED"));

            try
            {
                await Task.Run(() =>
                {
                    Microsoft.Playwright.Program.Main(new string[] { "install", "chromium" });
                }).ContinueWith(async (t) =>
                {
                    using var playwright = await Microsoft.Playwright.Playwright.CreateAsync();
                    await using var browser = await playwright.Chromium.LaunchAsync(new BrowserTypeLaunchOptions()
                    {
                        Headless = false
                    });

                    var page = await browser.NewPageAsync();
                    await page.GotoAsync("https://playwright.dev/dotnet");
                });
            }
            catch (Exception ex)
            {
                log.LogError(ex, "Error");
            }
        }
    }
}

Config file

// local.settings.json
{
  "IsEncrypted": false,
  "Values": {
    "AzureBlobStorage": "UseDevelopmentStorage=true",
    "FUNCTIONS_WORKER_RUNTIME": "dotnet"
  }
}

.csproj file

 // csproj
        ....
    <Target Name="FixPlaywrightCopyAfterBuild" AfterTargets="Build">
        <ItemGroup>
            <_BuildCopyItems Include="$(OutDir).playwright\**" />
        </ItemGroup>
        <Message Text="[Fix] Copying files to the nested bin folder of the azure function... $(OutDir)bin" Importance="high" />
        <Copy SourceFiles="@(_BuildCopyItems)" DestinationFiles="@(_BuildCopyItems->'$(OutDir)bin\.playwright\%(RecursiveDir)%(Filename)%(Extension)')" />
    </Target>

    <Target Name="FixPlaywrightCopyAfterPublish" AfterTargets="Publish">
        <ItemGroup>
            <_BuildCopyItems Include="$(PublishDir).playwright\**" />
        </ItemGroup>
        <Message Text="[Fix] Copying files to the nested bin folder of the azure function for publishing... $(PublishDir)bin" Importance="high" />
        <Copy SourceFiles="@(_BuildCopyItems)" DestinationFiles="@(_BuildCopyItems->'$(PublishDir)bin\.playwright\%(RecursiveDir)%(Filename)%(Extension)')" />
    </Target>

Steps

Expected The expected behavior is that the function will execute every 1 minute to open up the requested web page in a chromium instance.

Actual The actual result is a "System.IO.FileNotFoundException: 'Could not load file or assembly 'System.Text.Json, Version=7.0.0.0, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51" error when calling Playwright.CreateAsync. image

Are there any official examples of how to use playwright within an azure function as I can't seem to find much information on this.

Help with this would be greatly appreciated :)

mxschmitt commented 1 year ago

Do you mind sharing a small reproduction repository which we can run locally to reproduce this issue?

You can reproduce this locally if I understand you correctly?

mxschmitt commented 1 year ago

I can reproduce on a fresh Azure Functions created with Visual Studio Code, Potential fix (https://github.com/microsoft/playwright-dotnet/pull/2720) is a revert, just need to make sure it does not regress .NET 7 which is claimed to have fixed.