Skip to content

Conversation

@nvborisenko
Copy link
Member

@nvborisenko nvborisenko commented Nov 8, 2025

User description

🔗 Related Issues

Fixes #16539
Related to #14600

💥 What does this PR do?

Build for net462 framework to avoid binding redirects for System.Text.Json assembly. Selenium assembly now has correct reference to System.Text.Json v8.0.0.5.

🔧 Implementation Notes

Verified locally. Now installing Selenium.WebDriver package doesn't produce unnecessary binding redirection:

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

💡 Additional Considerations

It is still important to:

      <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>

But here we can do nothing, it is how .NET FX works.

🔄 Types of changes

  • Bug fix (backwards compatible)

PR Type

Bug fix, Enhancement


Description

  • Add net462 target framework support to avoid System.Text.Json binding redirects

  • Implement platform detection for net462 using Environment.OSVersion and Process.uname

  • Update NuGet package to include net462 assemblies with proper dependencies

  • Add framework assembly references for System.IO.Compression and System.Net.Http


Diagram Walkthrough

flowchart LR
  A["net462 Framework"] -->|"Platform Detection"| B["ResourceUtilities.cs"]
  A -->|"SeleniumManager Support"| C["SeleniumManager.cs"]
  A -->|"Build Configuration"| D["BUILD.bazel"]
  A -->|"Project Setup"| E["Selenium.WebDriver.csproj"]
  D -->|"Package Generation"| F["NuGet Package"]
  E -->|"Dependencies"| G["paket.nuget.bzl"]
Loading

File Walkthrough

Relevant files
Enhancement
ResourceUtilities.cs
Add net462 platform detection logic                                           

dotnet/src/webdriver/Internal/ResourceUtilities.cs

  • Add conditional compilation for net462 platform detection using
    Environment.OSVersion and Process.uname
  • Implement Unix platform detection via uname command to distinguish
    between macOS and Linux
  • Keep existing RuntimeInformation-based detection for .NET Core/.NET 5+
    frameworks
  • Add necessary using statements for System and System.Diagnostics
+37/-0   
SeleniumManager.cs
Add SeleniumManager net462 compatibility                                 

dotnet/src/webdriver/SeleniumManager.cs

  • Add conditional compilation blocks for net462, netstandard2.0, and
    net8.0_or_greater
  • Implement net462-specific platform detection defaulting to Windows
  • Replace RuntimeInformation.OSDescription with
    Environment.OSVersion.Platform for compatibility
  • Exclude native DLL search directories logic for net462 framework
+9/-3     
Dependencies
paket.nuget.bzl
Update NuGet package dependencies for net462                         

dotnet/paket.nuget.bzl

  • Update System.Numerics.Vectors from version 4.4.0 to 4.5.0
  • Add System.ValueTuple dependency for net462 in System.Text.Json
    package
  • Update System.Text.Json dependencies to include System.ValueTuple for
    net462 and higher frameworks
+3/-2     
Configuration changes
paket.dependencies
Add net462 to paket framework targets                                       

dotnet/paket.dependencies

  • Add net462 to the framework list in paket configuration
  • Update framework targets from net8.0,netstandard2.0 to
    net462,net8.0,netstandard2.0
+1/-1     
Selenium.WebDriver.csproj
Update project file for net462 support                                     

dotnet/src/webdriver/Selenium.WebDriver.csproj

  • Add net462 to TargetFrameworks property
  • Update System.Text.Json PackageReference condition to include net462
  • Add explicit framework assembly references for System.IO.Compression
    and System.Net.Http
+8/-3     
Selenium.WebDriver.nuspec
Add net462 package metadata and files                                       

dotnet/src/webdriver/Selenium.WebDriver.nuspec

  • Add net462 dependency group with System.Text.Json version 8.0.5
  • Add framework assembly declarations for System.IO.Compression and
    System.Net.Http
  • Include file mappings for net462 WebDriver.dll, pdb, and xml
    documentation
+9/-0     
Selenium.WebDriver.StrongNamed.nuspec
Add net462 strong-named package metadata                                 

dotnet/src/webdriver/Selenium.WebDriver.StrongNamed.nuspec

  • Add net462 dependency group with System.Text.Json version 8.0.5
  • Add framework assembly declarations for System.IO.Compression and
    System.Net.Http
  • Include file mappings for net462 WebDriver.StrongNamed assemblies with
    documentation
+9/-0     
Build configuration
BUILD.bazel
Add Bazel build targets for net462                                             

dotnet/src/webdriver/BUILD.bazel

  • Add new webdriver-net462 csharp_library target with net462 framework
  • Add new webdriver-net462-strongnamed csharp_library target for
    strong-named assembly
  • Include both targets in nuget_pack definitions for regular and
    strong-named packages
  • Add required NuGet dependencies for net462 builds
+75/-0   

@selenium-ci selenium-ci added C-dotnet .NET Bindings B-build Includes scripting, bazel and CI integrations labels Nov 8, 2025
@qodo-merge-pro
Copy link
Contributor

qodo-merge-pro bot commented Nov 8, 2025

PR Compliance Guide 🔍

Below is a summary of compliance checks for this PR:

Security Compliance
Command execution PATH risk

Description: Spawning the external process 'uname' without an absolute path in NET462 platform
detection may be intercepted or influenced by PATH hijacking on compromised systems.
ResourceUtilities.cs [129-145]

Referred Code
using (Process unameProcess = new Process())
{
    unameProcess.StartInfo.FileName = "uname";
    unameProcess.StartInfo.UseShellExecute = false;
    unameProcess.StartInfo.RedirectStandardOutput = true;
    unameProcess.Start();
    unameProcess.WaitForExit(1000);
    string output = unameProcess.StandardOutput.ReadToEnd();
    if (output.ToLowerInvariant().StartsWith("darwin"))
    {
        platformName = "mac";
    }
    else
    {
        platformName = "linux";
    }
}
Ticket Compliance
🟡
🎫 #16539
🟢 Provide a Selenium.WebDriver package variant that works on Windows PowerShell 5.1 with
.NET Framework 4.8 without failing to load System.Text.Json 8.0.0.0.
Ensure the assembly references System.Text.Json to a compatible fixed version so binding
redirects to 8.0.0.0 are not required.
Make Selenium Manager discoverable/usable when consumed from .NET Framework 4.8 scenarios.
Validate on a clean Windows PowerShell 5.1 + .NET Framework 4.8 machine that Import-Module
WebDriver.dll succeeds without binding redirects and Selenium Manager path probing works.
🟡
🎫 #14600
🟢 Prevent runtime from requesting System.Text.Json, Version=8.0.0.0 when using
Selenium.WebDriver > 4.23.0 in test runs.
Correct assembly reference to System.Text.Json so the located assembly manifest matches
(e.g., 8.0.5) and avoid manifest mismatch errors.
Run integration tests on Windows with Selenium.WebDriver built from this PR and confirm no
System.Text.Json 8.0.0.0 load errors occur.
Codebase Duplication Compliance
Codebase context is not defined

Follow the guide to enable codebase context checks.

Custom Compliance
🟢
Generic: Meaningful Naming and Self-Documenting Code

Objective: Ensure all identifiers clearly express their purpose and intent, making code
self-documenting

Status: Passed

Generic: Secure Error Handling

Objective: To prevent the leakage of sensitive system information through error messages while
providing sufficient detail for internal debugging.

Status: Passed

Generic: Secure Logging Practices

Objective: To ensure logs are useful for debugging and auditing without exposing sensitive
information like PII, PHI, or cardholder data.

Status: Passed

Generic: Comprehensive Audit Trails

Objective: To create a detailed and reliable record of critical system actions for security analysis
and compliance.

Status:
Action Logging: New platform-detection logic and process execution for NET462 does not include any audit
logging of actions or outcomes.

Referred Code
#if NET462
        // Unfortunately, detecting the currently running platform isn't as
        // straightforward as you might hope.
        // See: http://mono.wikia.com/wiki/Detecting_the_execution_platform
        // and https://msdn.microsoft.com/en-us/library/3a8hyw88(v=vs.110).aspx
        string platformName = "unknown";
        const int PlatformMonoUnixValue = 128;
        PlatformID platformId = Environment.OSVersion.Platform;
        if (platformId == PlatformID.Unix || platformId == PlatformID.MacOSX || (int)platformId == PlatformMonoUnixValue)
        {
            using (Process unameProcess = new Process())
            {
                unameProcess.StartInfo.FileName = "uname";
                unameProcess.StartInfo.UseShellExecute = false;
                unameProcess.StartInfo.RedirectStandardOutput = true;
                unameProcess.Start();
                unameProcess.WaitForExit(1000);
                string output = unameProcess.StandardOutput.ReadToEnd();
                if (output.ToLowerInvariant().StartsWith("darwin"))
                {
                    platformName = "mac";


 ... (clipped 12 lines)
Generic: Robust Error Handling and Edge Case Management

Objective: Ensure comprehensive error handling that provides meaningful context and graceful
degradation

Status:
Process Handling: The NET462 branch executes uname without try/catch, timeout/error checks, or fallback if
the process fails or is unavailable.

Referred Code
    using (Process unameProcess = new Process())
    {
        unameProcess.StartInfo.FileName = "uname";
        unameProcess.StartInfo.UseShellExecute = false;
        unameProcess.StartInfo.RedirectStandardOutput = true;
        unameProcess.Start();
        unameProcess.WaitForExit(1000);
        string output = unameProcess.StandardOutput.ReadToEnd();
        if (output.ToLowerInvariant().StartsWith("darwin"))
        {
            platformName = "mac";
        }
        else
        {
            platformName = "linux";
        }
    }
}
Generic: Security-First Input Validation and Data Handling

Objective: Ensure all data inputs are validated, sanitized, and handled securely to prevent
vulnerabilities

Status:
Command Execution: Spawning uname on NET462 without validating path or handling injection/availability risks
may introduce security concerns on certain hosts.

Referred Code
    using (Process unameProcess = new Process())
    {
        unameProcess.StartInfo.FileName = "uname";
        unameProcess.StartInfo.UseShellExecute = false;
        unameProcess.StartInfo.RedirectStandardOutput = true;
        unameProcess.Start();
        unameProcess.WaitForExit(1000);
        string output = unameProcess.StandardOutput.ReadToEnd();
        if (output.ToLowerInvariant().StartsWith("darwin"))
        {
            platformName = "mac";
        }
        else
        {
            platformName = "linux";
        }
    }
}
  • Update
Compliance status legend 🟢 - Fully Compliant
🟡 - Partial Compliant
🔴 - Not Compliant
⚪ - Requires Further Human Verification
🏷️ - Compliance label

@qodo-merge-pro
Copy link
Contributor

qodo-merge-pro bot commented Nov 8, 2025

PR Code Suggestions ✨

Explore these optional code suggestions:

CategorySuggestion                                                                                                                                    Impact
Possible issue
Fix incorrect target file paths
Suggestion Impact:The commit corrected the target filenames for net462 by removing the extra dot, aligning targets with the proper WebDriverStrongNamed filenames.

code diff:

-    <file src="lib/net462/WebDriver.StrongNamed.dll" target="lib/net462/WebDriverStrongNamed..dll" />
-    <file src="lib/net462/WebDriver.StrongNamed.pdb" target="lib/net462/WebDriverStrongNamed..pdb" />
-    <file src="lib/net462/WebDriver.StrongNamed.xml" target="lib/net462/WebDriverStrongNamed..xml" />
+    <file src="lib/net462/WebDriver.StrongNamed.dll" target="lib/net462/WebDriverStrongNamed.dll" />
+    <file src="lib/net462/WebDriver.StrongNamed.pdb" target="lib/net462/WebDriverStrongNamed.pdb" />
+    <file src="lib/net462/WebDriver.StrongNamed.xml" target="lib/net462/WebDriverStrongNamed.xml" />

Fix typos in the target attribute of file elements for the net462 framework in
Selenium.WebDriver.StrongNamed.nuspec by removing the extra dot in the
filenames.

dotnet/src/webdriver/Selenium.WebDriver.StrongNamed.nuspec [43-45]

-<file src="lib/net462/WebDriver.StrongNamed.dll" target="lib/net462/WebDriverStrongNamed..dll" />
-<file src="lib/net462/WebDriver.StrongNamed.pdb" target="lib/net462/WebDriverStrongNamed..pdb" />
-<file src="lib/net462/WebDriver.StrongNamed.xml" target="lib/net462/WebDriverStrongNamed..xml" />
+<file src="lib/net462/WebDriver.StrongNamed.dll" target="lib/net462/WebDriver.StrongNamed.dll" />
+<file src="lib/net462/WebDriver.StrongNamed.pdb" target="lib/net462/WebDriver.StrongNamed.pdb" />
+<file src="lib/net462/WebDriver.StrongNamed.xml" target="lib/net462/WebDriver.StrongNamed.xml" />

[Suggestion processed]

Suggestion importance[1-10]: 9

__

Why: The suggestion correctly identifies a typo in the NuGet package specification that would lead to incorrectly named files, breaking the package for the net462 target.

High
Fix incorrect platform detection logic

Fix incorrect platform detection for the NET462 target framework, which
currently assumes Windows. Implement proper OS detection using
Environment.OSVersion.Platform to support Linux and macOS via Mono.

dotnet/src/webdriver/SeleniumManager.cs [92-103]

 #elif NET462
-        var platform = SupportedPlatform.Windows;
+        SupportedPlatform? platform = null;
+        const int PlatformMonoUnixValue = 128;
+        PlatformID platformId = Environment.OSVersion.Platform;
+        if (platformId == PlatformID.Win32NT || platformId == PlatformID.Win32S || platformId == PlatformID.Win32Windows || platformId == PlatformID.WinCE)
+        {
+            platform = SupportedPlatform.Windows;
+        }
+        else if (platformId == PlatformID.Unix || (int)platformId == PlatformMonoUnixValue)
+        {
+            platform = SupportedPlatform.Linux;
+        }
+        else if (platformId == PlatformID.MacOSX)
+        {
+            platform = SupportedPlatform.MacOS;
+        }
 #endif
 
         var seleniumManagerFileName = platform switch
         {
             SupportedPlatform.Windows => "selenium-manager.exe",
             SupportedPlatform.Linux => "selenium-manager",
             SupportedPlatform.MacOS => "selenium-manager",
             _ => throw new PlatformNotSupportedException(
                 $"Selenium Manager doesn't support your runtime platform: {Environment.OSVersion.Platform}"),
         };
  • Apply / Chat
Suggestion importance[1-10]: 8

__

Why: The suggestion correctly identifies that hardcoding the platform as Windows for NET462 is a bug for non-Windows environments (like Mono) and proposes a correct fix using platform detection logic.

Medium
Prevent potential hang in process execution

Check the return value of unameProcess.WaitForExit() to prevent a potential hang
if the process times out. Handle the timeout by killing the process and setting
a default platform.

dotnet/src/webdriver/Internal/ResourceUtilities.cs [134-144]

 unameProcess.Start();
-unameProcess.WaitForExit(1000);
-string output = unameProcess.StandardOutput.ReadToEnd();
-if (output.ToLowerInvariant().StartsWith("darwin"))
+if (unameProcess.WaitForExit(1000))
 {
-    platformName = "mac";
+    string output = unameProcess.StandardOutput.ReadToEnd();
+    if (output.ToLowerInvariant().StartsWith("darwin"))
+    {
+        platformName = "mac";
+    }
+    else
+    {
+        platformName = "linux";
+    }
 }
 else
 {
+    // Default to linux on timeout and ensure process is killed.
     platformName = "linux";
+    try
+    {
+        if (!unameProcess.HasExited)
+        {
+            unameProcess.Kill();
+        }
+    }
+    catch
+    {
+        // Ignore exceptions during kill
+    }
 }
  • Apply / Chat
Suggestion importance[1-10]: 7

__

Why: The suggestion correctly identifies a potential application hang if the uname process times out and provides a robust solution to handle this edge case.

Medium
  • Update

@nvborisenko
Copy link
Member Author

Fails on EngFlow:

error CS0006: Metadata file '/mnt/engflow/worker/work/1/exec/external/rules_dotnet++targeting_packs_extension+nuget.microsoft.netframework.referenceassemblies.net462.v1.0.3/build/.NETFramework/v4.6.2/System.EnterpriseServices.Wrapper.dll' could not be found

Verified locally, the file exists on my local machine. @shs96c do you know?

@nvborisenko
Copy link
Member Author

It is bug in bazel: bazel-contrib/rules_dotnet#477, not related to EngFlow.

Reproduced locally on MacOS.

<None Include="..\..\..\common\images\selenium_logo_small.png" Pack="true" PackagePath="logo.png" Visible="false" />
</ItemGroup>

<ItemGroup>
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Only for net462

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

B-build Includes scripting, bazel and CI integrations C-dotnet .NET Bindings Review effort 3/5

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[🐛 Bug]: [PowerShell] .NET Framework 4.8: Could not load file or assembly 'System.Text.Json, Version=8.0.0.0

2 participants