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

[🐛 Bug]: OneTimeSetUp: System.IO.FileLoadException : Could not load file or assembly 'System.Text.Json, Version=8.0.0.0 #14600

Closed
Guitrum opened this issue Oct 14, 2024 · 16 comments
Labels
C-dotnet I-defect I-issue-template Applied to issues not following the template, or missing information.

Comments

@Guitrum
Copy link

Guitrum commented Oct 14, 2024

What happened?

Ever since updating Selenium.WebDriver past 4.23.0, running integration tests fails on the OneTimeSetUp. To be clear, I can run my full integration test suite on 4.23.0, but I get the same setup failures on 4.24.0 and 4.25.0. For some reason it seems to still be looking for System.Text.Json, Version=8.0.0.0 even though the dependency requires 8.0.4. I notice that when trying to install 8.0.0 manually, it says there is a high severity vulnerability which is why I assume the update to require 8.0.4 exists.

Something is still stuck trying to download System.Text.Json 8.0.0 even after the update of the webdriver beyond 4.23.0

How can we reproduce the issue?

Install Selenium.WebDriver v4.25.0 and try to run integration test suite.

Relevant log output

Message: 
OneTimeSetUp: System.IO.FileLoadException : Could not load file or assembly 'System.Text.Json, Version=8.0.0.0, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51' or one of its dependencies. The located assembly's manifest definition does not match the assembly reference. (Exception from HRESULT: 0x80131040)

  Stack Trace: 
SeleniumManager.BinaryPaths(String arguments)
DriverFinder.BinaryPaths()
DriverFinder.GetDriverPath()
ChromiumDriver.GenerateDriverServiceCommandExecutor(DriverService service, DriverOptions options, TimeSpan commandTimeout)
ChromiumDriver.ctor(ChromiumDriverService service, ChromiumOptions options, TimeSpan commandTimeout)
ChromeDriver.ctor(ChromeOptions options)
Setup.Init() line 42

Operating System

Windows 11

Selenium version

Selenium.WebDriver v4.25.0

What are the browser(s) and version(s) where you see this issue?

Chrome

What are the browser driver(s) and version(s) where you see this issue?

Selenium.WebDriver.ChromeDriver v129.0.6668.10000

Are you using Selenium Grid?

No response

Copy link

@Guitrum, thank you for creating this issue. We will troubleshoot it as soon as we can.


Info for maintainers

Triage this issue by using labels.

If information is missing, add a helpful comment and then I-issue-template label.

If the issue is a question, add the I-question label.

If the issue is valid but there is no time to troubleshoot it, consider adding the help wanted label.

If the issue requires changes or fixes from an external project (e.g., ChromeDriver, GeckoDriver, MSEdgeDriver, W3C), add the applicable G-* label, and it will provide the correct link and auto-close the issue.

After troubleshooting the issue, please add the R-awaiting answer label.

Thank you!

@Guitrum Guitrum changed the title [🐛 Bug]: [🐛 Bug]: OneTimeSetUp: System.IO.FileLoadException : Could not load file or assembly 'System.Text.Json, Version=8.0.0.0 Oct 14, 2024
@shbenzer
Copy link
Contributor

Have you tried updating System.Text.Json to 8.0.4 using your package manager?

@nvborisenko
Copy link
Member

@Guitrum we really need simple reproducible project where we can face this issue. Why? It works fine on my environment. The only one difference between 4.23 and 4.24 is that the latest one uses System.Text.Json instead of Newtonsoft.Json package. Theoretically and practically it just works. Your reproducible steps will help us to investigate a root cause of the issue to move furth.

@pujagani pujagani added the I-issue-template Applied to issues not following the template, or missing information. label Oct 16, 2024
Copy link

Hi, @Guitrum.
Please follow the issue template, we need more information to reproduce the issue.

Either a complete code snippet and URL/HTML (if more than one file is needed, provide a GitHub repo and instructions to run the code), the specific versions used, or a more detailed description to help us understand the issue.

Note: If you cannot share your code and URL/HTML, any complete code snippet and URL/HTML that reproduces the issue is good enough.

Reply to this issue when all information is provided, thank you.

@mvaneijken
Copy link

Got the same issue when using Selenium in Windows PowerShell 5.1. It gives the following error:
New-Object : Exception calling ".ctor" with "2" argument(s): "The type initializer for 'System.Text.Json ' threw an exception."

Tried versions 8.0.0, 8.0.4 and 8.0.5. Version 8.0.4 gives a slightly different error:

New-Object : Exception calling ".ctor" with "2" argument(s): "The type initializer for 'System.Text.Json.JsonSerializer ' threw an exception."

To invoke the web driver I'm executing the following code:

Add-Type -Path $("System.Text.Json.dll")
Add-Type -Path $("Webdriver.dll")

$EdgeOptions = New-Object  OpenQA.Selenium.Edge.EdgeOptions
$EdgeDriverService = [OpenQA.Selenium.Edge.EdgeDriverService]::CreateDefaultService("msedgedriver.exe")
$EdgeDriver = New-Object OpenQA.Selenium.Edge.EdgeDriver("msedgedriver.exe"), $EdgeOptions)

Versions used:
Windows 11 23H2 v10.0.22631.4317
Microsoft Edge v130.0.2849.46
PowerShell v5.1.22621.4249
msedgedriver.exe v130.0.2849.46
Webdriver.dll v4.25

@nvborisenko
Copy link
Member

@Guitrum @mvaneijken If somebody can rephrase steps to reproduce for me (as for dummy), I appreciate it.

@kcamp
Copy link

kcamp commented Nov 22, 2024

I have run into a very similar error as originally reported, but, at least in my exact case, this does not appear to be directly related to the Selenium assembly or packaging. In my case, taking on 4.26.1 (from a 3.x version) introduced the issue in the context of running some legacy MSTest v1 .orderedtest suites. I've since dropped back to 4.23.0 for the moment to work around this.

I have distilled down a reproducible example, which I'll discuss in "Issue 2", below. The key point here is most likely that we're targeting .NET 4.8. A secondary indicator is apt to be not automatically producing the assembly binding redirects.

I have created what should be a pretty straightforward (and hopefully consistent) repro case and pushed it to a repository -
kcamp/GH-14600-selenium-4-26-1-repro

Details of my machine -

OS Name:                   Microsoft Windows 10 Enterprise
OS Version:                10.0.19045 N/A Build 19045
Microsoft Visual Studio Professional 2022 (64-bit) - Current Version 17.10.6
Microsoft .NET Framework Version 4.8.09037

I have a few data points to share and expand on and will try to break them up as best I can 👍

Issue 1 - failure due to System.Text.Json - MSTest Deployment

First, the outright failure stemming from my [very specific!] MSTest scenario. This is a secondary presentation and in my opinion, is 100% unrelated to the issue in question, nor is it any sort of root cause. It's simply a presentation of an error that is an unfortunate red-herring. I do want to share it for completeness and in case it helps others start an investigation of their own.

The stack trace:

System.IO.FileNotFoundException: Could not load file or assembly 'System.Text.Json, Version=8.0.0.0, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51' or one of its dependencies. The system cannot find the file specified.
File name: 'System.Text.Json, Version=8.0.0.0, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51'
   at OpenQA.Selenium.Command.get_ParametersAsJsonString()
   at OpenQA.Selenium.Remote.HttpCommandExecutor.HttpRequestInfo..ctor(Uri serverUri, Command commandToExecute, HttpCommandInfo commandInfo)
   at OpenQA.Selenium.Remote.HttpCommandExecutor.<ExecuteAsync>d__34.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
   at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
   at OpenQA.Selenium.Remote.DriverServiceCommandExecutor.<ExecuteAsync>d__10.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
   at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
   at OpenQA.Selenium.WebDriver.<ExecuteAsync>d__63.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
   at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
   at OpenQA.Selenium.WebDriver.Execute(String driverCommandToExecute, Dictionary`2 parameters)
   at OpenQA.Selenium.WebDriver.StartSession(ICapabilities capabilities)
   at OpenQA.Selenium.WebDriver..ctor(ICommandExecutor executor, ICapabilities capabilities)
   at OpenQA.Selenium.Chrome.ChromeDriver..ctor(ChromeDriverService service, ChromeOptions options, TimeSpan commandTimeout)
   at MyNameSpace.InstantiateBrowser(IWebDriver& browser, BrowserType browserType, String downloadPath)

I could clearly see that the [presumably correct] System.Text.Json.dll assembly was in the \bin\Debug folder. Enabling fusion logging showed the issue to be the attempts to probe the shadow/deployment directory. MSTest is [https://stackoverflow.com/questions/19649632/all-assemblies-are-not-getting-copied-in-test-result-ms-test](not copying) the System.Text.Json.dll to that folder, which is leading to the failure. We can see the dump from fusion, below.

*** Assembly Binder Log Entry  (11/21/2024 @ 11:14:22 AM) ***

The operation failed.
Bind result: hr = 0x80070002. The system cannot find the file specified.

Assembly manager loaded from:  C:\Windows\Microsoft.NET\Framework\v4.0.30319\clr.dll
Running under executable  C:\Program Files (x86)\Microsoft Visual Studio\2019\Professional\Common7\IDE\QTAgent32_40.exe
--- A detailed error log follows. 

=== Pre-bind state information ===
LOG: DisplayName = System.Text.Json, Version=8.0.0.0, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51
 (Fully-specified)
LOG: Appbase = file:///C:/Path/To/TestProject/bin/debug/TestResults/Principal_HOSTNAME 2024-11-21 11_13_57/Out
LOG: Initial PrivatePath = NULL
LOG: Dynamic Base = NULL
LOG: Cache Base = NULL
LOG: AppName = QTAgent32_40.exe
Calling assembly : WebDriver, Version=4.0.0.0, Culture=neutral, PublicKeyToken=null.
===
LOG: This bind starts in default load context.
LOG: Using application configuration file: C:\Path\To\TestProject\bin\debug\TestResults\Principal_HOSTNAME 2024-11-21 11_13_57\Out\TestAssemblyName.DLL.config
LOG: Using host configuration file: 
LOG: Using machine configuration file from C:\Windows\Microsoft.NET\Framework\v4.0.30319\config\machine.config.
LOG: Post-policy reference: System.Text.Json, Version=8.0.0.0, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51
LOG: GAC Lookup was unsuccessful.
LOG: Attempting download of new URL file:///C:/Path/To/TestProject/bin/debug/TestResults/Principal_HOSTNAME 2024-11-21 11_13_57/Out/System.Text.Json.DLL.
LOG: Attempting download of new URL file:///C:/Path/To/TestProject/bin/debug/TestResults/Principal_HOSTNAME 2024-11-21 11_13_57/Out/System.Text.Json/System.Text.Json.DLL.
LOG: Attempting download of new URL file:///C:/Path/To/TestProject/bin/debug/TestResults/Principal_HOSTNAME 2024-11-21 11_13_57/Out/System.Text.Json.EXE.
LOG: Attempting download of new URL file:///C:/Path/To/TestProject/bin/debug/TestResults/Principal_HOSTNAME 2024-11-21 11_13_57/Out/System.Text.Json/System.Text.Json.EXE.
LOG: All probing URLs attempted and failed.

📣 For anyone finding this and attempting to debug through it, the best thing to do is probably going to be to enable fusion logging to better understand what exactly is being probed/discovered and what the underlying mismatch might be.

  • In the case of @Guitrum they could see what is/is not resolving.
  • In the case of @mvaneijken I'd enable fusion logging for all assembly binds to see what version of the assembly is loading, which may speak to what the type initialization exception might be about.

Issue 2 - Visual Studio Test Explorer failure due to System.Runtime.CompilerServices.Unsafe

In an effort to create a repro case, "out of the box" in a new project, I failed. Visual Studio appears to do what's right and it all works. I tried both net8.0 and net48. However, some more digging and thinking and I was able to get it.
This goes back to the explicit suppression of the assembly binding redirect generation, mentioned above. Absent the redirects, this is the exception I get when running MSTest.TestFramework tests in VS2022 Test Explorer and presents with the following failure:

  Message: 
Initialization method selenium_system_text_json_repro.SeleniumSystemTextJsonRepro.Setup threw exception. System.IO.FileLoadException: Could not load file or assembly 'System.Runtime.CompilerServices.Unsafe, Version=4.0.4.1, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a' or one of its dependencies. The located assembly's manifest definition does not match the assembly reference. (Exception from HRESULT: 0x80131040).
TestCleanup method selenium_system_text_json_repro.SeleniumSystemTextJsonRepro.TearDown threw exception. System.NullReferenceException: Object reference not set to an instance of an object..

  Stack Trace: 
MemoryExtensions.AsSpan(String text)
JsonEncodedText.Encode(String value, JavaScriptEncoder encoder)
SeleniumManagerSerializerContext.cctor()
TestCleanup Stack Trace
SeleniumSystemTextJsonRepro.TearDown() line 55

This error is suppressed (at least for me) when creating a fresh .csproj and the project automatically generates assembly binding redirects. I had to specify <AutoGenerateBindingRedirects>false</AutoGenerateBindingRedirects> in my repro project to emulate the example I am seeing in our product regression tests.

It is interesting, though, that if we are observing this in the fusion log, we can also see that there's a assembly load error reported for System.Text.Json, it's just not bubbling to the top of the test failure.

While the error surfacing in the runner is related to System.Runtime.CompilerServices.Unsafe, we can see fusion logs for both that assembly and System.Text.Json both.

System.Runtime.CompilerServices.Unsafe

*** Assembly Binder Log Entry  (11/22/2024 @ 9:49:58 AM) ***

The operation failed.
Bind result: hr = 0x80131040. No description available.

Assembly manager loaded from:  C:\Windows\Microsoft.NET\Framework64\v4.0.30319\clr.dll
Running under executable  D:\Program Files\Microsoft Visual Studio\2022\Professional\Common7\IDE\Extensions\TestPlatform\testhost.net48.exe
--- A detailed error log follows. 

=== Pre-bind state information ===
LOG: DisplayName = System.Runtime.CompilerServices.Unsafe, Version=4.0.4.1, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a
 (Fully-specified)
LOG: Appbase = file:///C:/Users/kcamp/source/repos/selenium-repro/selenium-system-text-json-repro-ms/bin/Debug/net48
LOG: Initial PrivatePath = NULL
LOG: Dynamic Base = NULL
LOG: Cache Base = NULL
LOG: AppName = NULL
Calling assembly : (Unknown).
===
LOG: This bind starts in default load context.
LOG: Using application configuration file: D:\Program Files\Microsoft Visual Studio\2022\Professional\Common7\IDE\Extensions\TestPlatform\testhost.net48.exe.Config
LOG: Using host configuration file: 
LOG: Using machine configuration file from C:\Windows\Microsoft.NET\Framework64\v4.0.30319\config\machine.config.
LOG: GAC Lookup was unsuccessful.
LOG: Attempting download of new URL file:///C:/Users/kcamp/source/repos/selenium-repro/selenium-system-text-json-repro-ms/bin/Debug/net48/System.Runtime.CompilerServices.Unsafe.DLL.
LOG: Assembly download was successful. Attempting setup of file: C:\Users\kcamp\source\repos\selenium-repro\selenium-system-text-json-repro-ms\bin\Debug\net48\System.Runtime.CompilerServices.Unsafe.dll
LOG: Entering run-from-source setup phase.
LOG: Assembly Name is: System.Runtime.CompilerServices.Unsafe, Version=6.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a
WRN: Comparing the assembly name resulted in the mismatch: Major Version
ERR: The assembly reference did not match the assembly definition found.
ERR: Run-from-source setup phase failed with hr = 0x80131040.
ERR: Failed to complete setup of assembly (hr = 0x80131040). Probing terminated.

System.Text.Json

*** Assembly Binder Log Entry  (11/22/2024 @ 9:49:58 AM) ***

The operation failed.
Bind result: hr = 0x80131040. No description available.

Assembly manager loaded from:  C:\Windows\Microsoft.NET\Framework64\v4.0.30319\clr.dll
Running under executable  D:\Program Files\Microsoft Visual Studio\2022\Professional\Common7\IDE\Extensions\TestPlatform\testhost.net48.exe
--- A detailed error log follows. 

=== Pre-bind state information ===
LOG: DisplayName = System.Text.Json, Version=8.0.0.0, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51
 (Fully-specified)
LOG: Appbase = file:///C:/Users/kcamp/source/repos/selenium-repro/selenium-system-text-json-repro-ms/bin/Debug/net48
LOG: Initial PrivatePath = NULL
LOG: Dynamic Base = NULL
LOG: Cache Base = NULL
LOG: AppName = NULL
Calling assembly : WebDriver, Version=4.0.0.0, Culture=neutral, PublicKeyToken=null.
===
LOG: This bind starts in default load context.
LOG: Using application configuration file: D:\Program Files\Microsoft Visual Studio\2022\Professional\Common7\IDE\Extensions\TestPlatform\testhost.net48.exe.Config
LOG: Using host configuration file: 
LOG: Using machine configuration file from C:\Windows\Microsoft.NET\Framework64\v4.0.30319\config\machine.config.
LOG: Post-policy reference: System.Text.Json, Version=8.0.0.0, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51
LOG: GAC Lookup was unsuccessful.
LOG: Attempting download of new URL file:///C:/Users/kcamp/source/repos/selenium-repro/selenium-system-text-json-repro-ms/bin/Debug/net48/System.Text.Json.DLL.
LOG: Assembly download was successful. Attempting setup of file: C:\Users\kcamp\source\repos\selenium-repro\selenium-system-text-json-repro-ms\bin\Debug\net48\System.Text.Json.dll
LOG: Entering run-from-source setup phase.
LOG: Assembly Name is: System.Text.Json, Version=8.0.0.4, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51
WRN: Comparing the assembly name resulted in the mismatch: Revision Number
ERR: The assembly reference did not match the assembly definition found.
ERR: Run-from-source setup phase failed with hr = 0x80131040.
ERR: Failed to complete setup of assembly (hr = 0x80131040). Probing terminated.

To make the test work, we can add in the assembly binding redirect for just System.Runtime.CompilerServices.Unsafe (below). It is important to note that we will still see the fusion log for the failed resolution of System.Text.Json, but this seems to be a non-critical issue, at least in the simplified case. I suspect that adding the redirect for System.Text.Json would be the correct thing to do, despite our stripped down example not seeming to have issues.

  <runtime>
    <assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
      <dependentAssembly>
        <assemblyIdentity name="System.Runtime.CompilerServices.Unsafe" publicKeyToken="b03f5f7f11d50a3a" culture="neutral" />
        <bindingRedirect oldVersion="0.0.0.0-6.0.0.0" newVersion="6.0.0.0" />
      </dependentAssembly>
    </assemblyBinding>
  </runtime>

Issue 3 - VSTest.Console failure due to System.Text.Json

An interesting behavior emerged when I was authoring some Cake scripts to help your team reproduce these - I was able to accurately reproduce the behavior seen in NUnit (below, Issue 4) from the console in VSTest. It turns out that in Issue 2, as I had alluded to, we need to place the redirect for System.Text.Json as well to make the tests run from the command line.

========================================
Test-VSTest
========================================
Executing task: Test-VSTest
Executing: "C:/Users/kcamp/source/repos/selenium-repro/tools/Microsoft.TestPlatform.17.12.0/tools/net462/Common7/IDE/Extensions/TestPlatform/vstest.console.exe" "C:/Users/kcamp/source/repos/selenium-repro/selenium-system-text-json-repro-ms/bin/Debug/net48/selenium-system-text-json-repro-ms.dll"
VSTest version 17.12.0 (x64)

Starting test execution, please wait...
A total of 1 test files matched the specified pattern.
  Failed BasicChromeTest [317 ms]
  Error Message:
   Initialization method selenium_system_text_json_repro_ms.SeleniumSystemTextJsonRepro.Setup threw exception. System.IO.FileLoadException: Could not load file or assembly 'System.Text.Json, Version=8.0.0.0, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51' or one of its dependencies. The located assembly's manifest definition does not match the assembly reference. (Exception from HRESULT: 0x80131040).
TestCleanup method selenium_system_text_json_repro_ms.SeleniumSystemTextJsonRepro.TearDown threw exception. System.NullReferenceException: Object reference not set to an instance of an object..
  Stack Trace:
      at OpenQA.Selenium.SeleniumManager..cctor()

TestCleanup Stack Trace
   at selenium_system_text_json_repro_ms.SeleniumSystemTextJsonRepro.TearDown() in C:\Users\kcamp\source\repos\selenium-repro\selenium-system-text-json-repro-ms\SeleniumSystemTextJsonRepro.cs:line 55

Adding both redirects resolves this error:

<runtime>
    <assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
      <dependentAssembly>
        <assemblyIdentity name="System.Runtime.CompilerServices.Unsafe" publicKeyToken="b03f5f7f11d50a3a" culture="neutral" />
        <bindingRedirect oldVersion="0.0.0.0-6.0.0.0" newVersion="6.0.0.0" />
      </dependentAssembly>
      <dependentAssembly>
        <assemblyIdentity name="System.Text.Json" publicKeyToken="cc7b13ffcd2ddd51" culture="neutral" />
        <bindingRedirect oldVersion="0.0.0.0-8.0.0.4" newVersion="8.0.0.4" />
      </dependentAssembly>
    </assemblyBinding>
  </runtime>

Issue 4 - NUnit failure due to System.Text.Json

Given what I learned in the second issue, I was able to reproduce (I am pretty sure) the exact case that @Guitrum reported.

  Message: 
OneTimeSetUp: System.TypeInitializationException : The type initializer for 'OpenQA.Selenium.SeleniumManager' threw an exception.
  ----> System.IO.FileLoadException : Could not load file or assembly 'System.Text.Json, Version=8.0.0.0, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51' or one of its dependencies. The located assembly's manifest definition does not match the assembly reference. (Exception from HRESULT: 0x80131040)

  Stack Trace: 
SeleniumManager.BinaryPaths(String arguments)
DriverFinder.BinaryPaths()
DriverFinder.GetDriverPath()
ChromiumDriver.GenerateDriverServiceCommandExecutor(DriverService service, DriverOptions options, TimeSpan commandTimeout)
ChromiumDriver.ctor(ChromiumDriverService service, ChromiumOptions options, TimeSpan commandTimeout)
ChromeDriver.ctor(ChromeDriverService service, ChromeOptions options, TimeSpan commandTimeout)
SeleniumSystemTextJsonRepro.Setup() line 49
--FileLoadException
SeleniumManager.cctor()

This one, unlike the previous issue, required an assembly binding redirect for both assemblies in order to work, but once in place, the test does work without issue.

  <runtime>
    <assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
      <dependentAssembly>
        <assemblyIdentity name="System.Runtime.CompilerServices.Unsafe" publicKeyToken="b03f5f7f11d50a3a" culture="neutral" />
        <bindingRedirect oldVersion="0.0.0.0-6.0.0.0" newVersion="6.0.0.0" />
      </dependentAssembly>
      <dependentAssembly>
        <assemblyIdentity name="System.Text.Json" publicKeyToken="cc7b13ffcd2ddd51" culture="neutral" />
        <bindingRedirect oldVersion="0.0.0.0-8.0.0.4" newVersion="8.0.0.4" />
      </dependentAssembly>
    </assemblyBinding>
  </runtime>

Hope this helps, if there is anything I can help to clarify, please tag me.

@nvborisenko
Copy link
Member

To sum-up: this is how assembly resolving is working in .net framework, and selenium is not an exception. As a developer, you should become familiar with it, especially with https://learn.microsoft.com/en-us/dotnet/framework/configure-apps/redirect-assembly-versions. If you use .net core, you will never face this issue.

@kcamp do you have any specific issue I may help to you?

@kcamp
Copy link

kcamp commented Nov 22, 2024

@nvborisenko No, there is nothing I need assistance with. I wanted to provide the repro scenario and share the investigation I did. Thank you for checking 👍

I do think I better understand why this is happening, though. I've set up a simple project build using the same System.Text.Json 8.0.4 reference that the Selenium.WebDriver project is using and examined the way things are being resolved and referenced.

TL;DR - There's an assembly version mismatch between target frameworks in the System.Text.Json package which makes it 100% necessary to add assembly binding redirects to your testing configuration file (or configure tooling to do it for you) when you're targeting .NET Framework.

--

Examining the binary logger output, we can see that the FusionName of the lib/netstandard2.0/System.Text.Json.dll assembly in the System.Text.Json package is reflected as FusionName = System.Text.Json, Version=8.0.0.0, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51

image

If we browse the actual System.Text.Json 8.0.4 package in dotPeek or your favorite tool, it seems that the assemblies have a different assembly version when loaded from /lib/net462/

image

This is reflected [correctly] in the Selenium.WebDriver packaging/binaries.

image

However, when we're building a project targeting .NET 4.8, we're resolving the file at /lib/net462 and copying that to the output path. This is, I think, where the explicit need for the redirect is coming from, at least for the System.Text.Json assembly. The Selenium.WebDriver assembly, targeting only netstandard2.0 knows the assembly reference as System.Text.Json 8.0.0.0 and a framework project is getting a differently versioned assembly in the output path [working directory]. Reference the excerpted build log from a .NET 4.8 build -

image

Given all this, I am pretty sure that any suggestion or attempt to take on a top-level reference to System.Text.Json 8.0.4 (or whatever the current major version may be) will never provide a solution for .NET Framework targets [when the /lib/net462 assembly is being chosen] due to the mismatch. We'll always need to rely on the assembly binding redirects.

I believe this difference between assembly versions in System.Text.Json is reported & explained in dotnet/runtime - Issue 78754.

So this really comes down to the auto-generation of the assembly binding redirects for the .NET Framework class libraries.
I referenced this issue for a little hand there and came up with a working solution to make a framework project work correctly. I've pushed this to a branch in my original repro in case it helps others.
https://github.com/kcamp/GH-14600-selenium-4-26-1-repro/tree/net-framework-workaround

<Project Sdk="Microsoft.NET.Sdk">

  <PropertyGroup>
    <TargetFramework>net48</TargetFramework>
    <RootNamespace>selenium_system_text_json_repro_nunit</RootNamespace>
    <ImplicitUsings>enable</ImplicitUsings>
    <Nullable>enable</Nullable>
    <LangVersion>10.0</LangVersion>
    <IsPackable>false</IsPackable>
    <OutputType>Library</OutputType>
    <AutoGenerateBindingRedirects>true</AutoGenerateBindingRedirects>
  </PropertyGroup>

  <ItemGroup>
    <PackageReference Include="NUnit" Version="4.2.2" />
    <PackageReference Include="NUnit3TestAdapter" Version="4.6.0" />
    <PackageReference Include="Selenium.Support" Version="4.26.1" />
    <PackageReference Include="Selenium.WebDriver" Version="4.26.1" />
    <PackageReference Include="Selenium.WebDriver.ChromeDriver" Version="131.0.6778.8500" />
  </ItemGroup>

  <!-- 
    This forces the generation of assembly binding redirects 
    for class libraries - see https://github.com/dotnet/msbuild/issues/1310
  -->
  <Target Name="ForceGenerationOfBindingRedirects"
          AfterTargets="ResolveAssemblyReferences"
          BeforeTargets="GenerateBindingRedirects"
          Condition="'$(AutoGenerateBindingRedirects)' == 'true'">
    <PropertyGroup>
      <!-- Needs to be set in a target because it has to be set after the initial evaluation in the common targets -->
      <GenerateBindingRedirectsOutputType>true</GenerateBindingRedirectsOutputType>
    </PropertyGroup>
  </Target>

</Project>

Hope this helps explain things for anyone else coming across this issue. Fingers crossed we all continue to solve our tech debt and get off the full Framework! 🤞

@nvborisenko
Copy link
Member

Only one question:

<dependentAssembly>
        <assemblyIdentity name="System.Text.Json" publicKeyToken="cc7b13ffcd2ddd51" culture="neutral" />
        <bindingRedirect oldVersion="0.0.0.0-8.0.0.4" newVersion="8.0.0.4" />
      </dependentAssembly>

why 8.0.0.4? It should be 8.0.0.0

(I know .net framework 4.6.2 is bad in terms of compatibility with netstadarad2.0, seems you use .net 4.8)

@nvborisenko
Copy link
Member

nvborisenko commented Nov 22, 2024

Figured it out, this is really strong name version of System.Text.Json.dll assembly for net462.

@kcamp
Copy link

kcamp commented Nov 22, 2024

Yeah, you figured it out and beat me by a couple of minutes. I'll still share the details (plus another workaround) -

--

It's 8.0.0.4 because that is what matches the deployed assembly - MSBuild is choosing the /lib/net462 assembly over the netstandard2.0 assembly (and copying it to the output directory) and that assembly is 8.0.0.4. I don't know why MSBuild is making that decision - I do see this issue with a similar question, but no resolution or explanation.

The Selenium.WebDriver assembly references 8.0.0.0 because it's multi-targeting, and that's what's it's attempting to resolve at runtime because the assembly version of the netstandard2.0 is 8.0.0.0. If all of the assemblies in the System.Text.Json package were versioned consistently, we wouldn't need the assembly binding redirect.

When we're targeting .NET 4.8 (I would surmise any full framework), we're resolving 8.0.0.4. Now that I've wired up my integration test projects with the right bits to force them to emit the assembly binding redirects, that snippet of the assembly binding redirect is what MSBuild emits, verbatim.

If I take the comment from issue I linked above and incorporate it in my repro case, it suppresses the assembly binding redirect entirely and the test works correctly in NUnit.

<Project Sdk="Microsoft.NET.Sdk">

  <PropertyGroup>
    <TargetFramework>net48</TargetFramework>
    <RootNamespace>selenium_system_text_json_repro_nunit</RootNamespace>
    <ImplicitUsings>enable</ImplicitUsings>
    <Nullable>enable</Nullable>
    <LangVersion>10.0</LangVersion>
    <IsPackable>false</IsPackable>
    <OutputType>Library</OutputType>
    <AutoGenerateBindingRedirects>true</AutoGenerateBindingRedirects>
  </PropertyGroup>

  <ItemGroup>
    <PackageReference Include="NUnit" Version="4.2.2" />
    <PackageReference Include="NUnit3TestAdapter" Version="4.6.0" />
    <PackageReference Include="Selenium.Support" Version="4.26.1" />
    <PackageReference Include="Selenium.WebDriver" Version="4.26.1" />
    <PackageReference Include="Selenium.WebDriver.ChromeDriver" Version="131.0.6778.8500" />
    <PackageReference Include="System.Text.Json" Version="8.0.4" GeneratePathProperty="true" ExcludeAssets="Compile;Runtime;Build" />
  </ItemGroup>

  <ItemGroup>
    <!-- 
    Force our reference to the netstandard2.0 8.0.0.0 version of the assembly 
    and avoid the need for an assembly binding redirect for System.Text.Json
    -->
    <Reference Include="System.Text.Json">
      <HintPath>$(PkgSystem_Text_Json)\lib\netstandard2.0\System.Text.Json.dll</HintPath>
    </Reference>
  </ItemGroup>

  <!-- 
    This forces the generation of assembly binding redirects 
    for class libraries - see https://github.com/dotnet/msbuild/issues/1310
  -->
  <Target Name="ForceGenerationOfBindingRedirects"
          AfterTargets="ResolveAssemblyReferences"
          BeforeTargets="GenerateBindingRedirects"
          Condition="'$(AutoGenerateBindingRedirects)' == 'true'">
    <PropertyGroup>
      <!-- Needs to be set in a target because it has to be set after the initial evaluation in the common targets -->
      <GenerateBindingRedirectsOutputType>true</GenerateBindingRedirectsOutputType>
    </PropertyGroup>
  </Target>

</Project>

@nvborisenko
Copy link
Member

nvborisenko commented Nov 22, 2024

@kcamp please help me to advise all who faced this issue in "old .net framework" - just verify binding redirects. Is it true?

@kcamp
Copy link

kcamp commented Nov 22, 2024

Yes, exactly. For those users targeting full framework, it will be necessary to ensure that they're either placing the redirects manually or re-working their project files to automatically generate them.

@nvborisenko
Copy link
Member

Thank you man!

@Guitrum you will be able to resolve the issue via correcting binding redirects.
@mvaneijken you miss some dependency required by System.Text.Json package.

@nvborisenko
Copy link
Member

nvborisenko commented Nov 22, 2024

I would like to freeze this conversation. If somebody faces similar issue, please post new one referencing to this.

Sorry, don't hesitate to describe your situation in new issue.

@SeleniumHQ SeleniumHQ locked as resolved and limited conversation to collaborators Nov 22, 2024
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
C-dotnet I-defect I-issue-template Applied to issues not following the template, or missing information.
Projects
None yet
Development

No branches or pull requests

7 participants