From a72b3a9ccc86cc001f84fa449c31c0862eb72113 Mon Sep 17 00:00:00 2001 From: Michael Render Date: Wed, 3 Dec 2025 15:35:33 -0500 Subject: [PATCH] [dotnet] Replace stateful BiDi converters with thread-static BiDi instance --- dotnet/src/webdriver/BiDi/BiDi.cs | 9 --------- dotnet/src/webdriver/BiDi/Broker.cs | 8 ++++++++ dotnet/src/webdriver/BiDi/Browser/UserContext.cs | 3 +++ .../webdriver/BiDi/BrowsingContext/BrowsingContext.cs | 2 ++ .../Json/Converters/BrowserUserContextConverter.cs | 10 ++-------- .../BiDi/Json/Converters/BrowsingContextConverter.cs | 10 ++-------- .../BiDi/Json/Converters/CollectorConverter.cs | 10 ++-------- .../webdriver/BiDi/Json/Converters/HandleConverter.cs | 10 ++-------- .../BiDi/Json/Converters/InterceptConverter.cs | 10 ++-------- .../BiDi/Json/Converters/InternalIdConverter.cs | 10 ++-------- .../BiDi/Json/Converters/PreloadScriptConverter.cs | 10 ++-------- .../webdriver/BiDi/Json/Converters/RealmConverter.cs | 10 ++-------- .../BiDi/Json/Converters/WebExtensionConverter.cs | 10 ++-------- dotnet/src/webdriver/BiDi/Network/Collector.cs | 3 +++ dotnet/src/webdriver/BiDi/Network/Intercept.cs | 3 +++ dotnet/src/webdriver/BiDi/Script/Handle.cs | 4 ++++ dotnet/src/webdriver/BiDi/Script/InternalId.cs | 4 ++++ dotnet/src/webdriver/BiDi/Script/PreloadScript.cs | 3 +++ dotnet/src/webdriver/BiDi/Script/Realm.cs | 4 ++++ dotnet/src/webdriver/BiDi/WebExtension/Extension.cs | 3 +++ 20 files changed, 55 insertions(+), 81 deletions(-) diff --git a/dotnet/src/webdriver/BiDi/BiDi.cs b/dotnet/src/webdriver/BiDi/BiDi.cs index a6593ab29db86..477cc6d40d21b 100644 --- a/dotnet/src/webdriver/BiDi/BiDi.cs +++ b/dotnet/src/webdriver/BiDi/BiDi.cs @@ -103,16 +103,7 @@ private JsonSerializerOptions GetJsonOptions() NumberHandling = JsonNumberHandling.AllowNamedFloatingPointLiterals | JsonNumberHandling.AllowReadingFromString, Converters = { - new BrowsingContextConverter(this), - new BrowserUserContextConverter(this), - new CollectorConverter(this), - new InterceptConverter(this), - new HandleConverter(this), - new InternalIdConverter(this), - new PreloadScriptConverter(this), - new RealmConverter(this), new DateTimeOffsetConverter(), - new WebExtensionConverter(this), } }; } diff --git a/dotnet/src/webdriver/BiDi/Broker.cs b/dotnet/src/webdriver/BiDi/Broker.cs index 6e74edcfb5522..ddd02fa242173 100644 --- a/dotnet/src/webdriver/BiDi/Broker.cs +++ b/dotnet/src/webdriver/BiDi/Broker.cs @@ -50,6 +50,12 @@ public sealed class Broker : IAsyncDisposable private Task? _eventEmitterTask; private CancellationTokenSource? _receiveMessagesCancellationTokenSource; + + internal static BiDi? ThreadStaticBiDi => _threadStaticBiDi; + + [ThreadStatic] + private static BiDi? _threadStaticBiDi; + internal Broker(BiDi bidi, Uri url) { _bidi = bidi; @@ -276,8 +282,10 @@ private void ProcessReceivedMessage(byte[]? data) { try { + _threadStaticBiDi = _bidi; var commandResult = JsonSerializer.Deserialize(ref resultReader, command.JsonResultTypeInfo) ?? throw new JsonException("Remote end returned null command result in the 'result' property."); + _threadStaticBiDi = null; command.TaskCompletionSource.SetResult((EmptyResult)commandResult); } diff --git a/dotnet/src/webdriver/BiDi/Browser/UserContext.cs b/dotnet/src/webdriver/BiDi/Browser/UserContext.cs index 46066271be9e1..3e3ec1b68f439 100644 --- a/dotnet/src/webdriver/BiDi/Browser/UserContext.cs +++ b/dotnet/src/webdriver/BiDi/Browser/UserContext.cs @@ -17,11 +17,14 @@ // under the License. // +using OpenQA.Selenium.BiDi.Json.Converters; using System; +using System.Text.Json.Serialization; using System.Threading.Tasks; namespace OpenQA.Selenium.BiDi.Browser; +[JsonConverter(typeof(BrowserUserContextConverter))] public sealed class UserContext : IEquatable, IAsyncDisposable { private readonly BiDi _bidi; diff --git a/dotnet/src/webdriver/BiDi/BrowsingContext/BrowsingContext.cs b/dotnet/src/webdriver/BiDi/BrowsingContext/BrowsingContext.cs index 24fdc57b0b1bd..f221d80784ea1 100644 --- a/dotnet/src/webdriver/BiDi/BrowsingContext/BrowsingContext.cs +++ b/dotnet/src/webdriver/BiDi/BrowsingContext/BrowsingContext.cs @@ -17,6 +17,7 @@ // under the License. // +using OpenQA.Selenium.BiDi.Json.Converters; using System; using System.Text.Json.Serialization; using System.Threading; @@ -24,6 +25,7 @@ namespace OpenQA.Selenium.BiDi.BrowsingContext; +[JsonConverter(typeof(BrowsingContextConverter))] public sealed class BrowsingContext { internal BrowsingContext(BiDi bidi, string id) diff --git a/dotnet/src/webdriver/BiDi/Json/Converters/BrowserUserContextConverter.cs b/dotnet/src/webdriver/BiDi/Json/Converters/BrowserUserContextConverter.cs index e660c9843f086..3d5fa2e47222a 100644 --- a/dotnet/src/webdriver/BiDi/Json/Converters/BrowserUserContextConverter.cs +++ b/dotnet/src/webdriver/BiDi/Json/Converters/BrowserUserContextConverter.cs @@ -26,18 +26,12 @@ namespace OpenQA.Selenium.BiDi.Json.Converters; internal class BrowserUserContextConverter : JsonConverter { - private readonly BiDi _bidi; - - public BrowserUserContextConverter(BiDi bidi) - { - _bidi = bidi; - } - public override UserContext? Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) { var id = reader.GetString(); + var bidi = Broker.ThreadStaticBiDi ?? throw new InvalidOperationException("No BiDi set"); - return new UserContext(_bidi, id!); + return new UserContext(bidi, id!); } public override void Write(Utf8JsonWriter writer, UserContext value, JsonSerializerOptions options) diff --git a/dotnet/src/webdriver/BiDi/Json/Converters/BrowsingContextConverter.cs b/dotnet/src/webdriver/BiDi/Json/Converters/BrowsingContextConverter.cs index 208b2698ad01f..59ecf7ecea045 100644 --- a/dotnet/src/webdriver/BiDi/Json/Converters/BrowsingContextConverter.cs +++ b/dotnet/src/webdriver/BiDi/Json/Converters/BrowsingContextConverter.cs @@ -25,18 +25,12 @@ namespace OpenQA.Selenium.BiDi.Json.Converters; internal class BrowsingContextConverter : JsonConverter { - private readonly BiDi _bidi; - - public BrowsingContextConverter(BiDi bidi) - { - _bidi = bidi; - } - public override BrowsingContext.BrowsingContext? Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) { var id = reader.GetString(); + var bidi = Broker.ThreadStaticBiDi ?? throw new InvalidOperationException("No BiDi set"); - return new BrowsingContext.BrowsingContext(_bidi, id!); + return new BrowsingContext.BrowsingContext(bidi, id!); } public override void Write(Utf8JsonWriter writer, BrowsingContext.BrowsingContext value, JsonSerializerOptions options) diff --git a/dotnet/src/webdriver/BiDi/Json/Converters/CollectorConverter.cs b/dotnet/src/webdriver/BiDi/Json/Converters/CollectorConverter.cs index 9f77d0f03fcbc..9d73e72424eed 100644 --- a/dotnet/src/webdriver/BiDi/Json/Converters/CollectorConverter.cs +++ b/dotnet/src/webdriver/BiDi/Json/Converters/CollectorConverter.cs @@ -26,18 +26,12 @@ namespace OpenQA.Selenium.BiDi.Json.Converters; internal class CollectorConverter : JsonConverter { - private readonly BiDi _bidi; - - public CollectorConverter(BiDi bidi) - { - _bidi = bidi; - } - public override Collector? Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) { var id = reader.GetString(); + var bidi = Broker.ThreadStaticBiDi ?? throw new InvalidOperationException("No BiDi set"); - return new Collector(_bidi, id!); + return new Collector(bidi, id!); } public override void Write(Utf8JsonWriter writer, Collector value, JsonSerializerOptions options) diff --git a/dotnet/src/webdriver/BiDi/Json/Converters/HandleConverter.cs b/dotnet/src/webdriver/BiDi/Json/Converters/HandleConverter.cs index 852a3d925cc00..a8f2cba09cf16 100644 --- a/dotnet/src/webdriver/BiDi/Json/Converters/HandleConverter.cs +++ b/dotnet/src/webdriver/BiDi/Json/Converters/HandleConverter.cs @@ -26,18 +26,12 @@ namespace OpenQA.Selenium.BiDi.Json.Converters; internal class HandleConverter : JsonConverter { - private readonly BiDi _bidi; - - public HandleConverter(BiDi bidi) - { - _bidi = bidi; - } - public override Handle? Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) { var id = reader.GetString(); + var bidi = Broker.ThreadStaticBiDi ?? throw new InvalidOperationException("No BiDi set"); - return new Handle(_bidi, id!); + return new Handle(bidi, id!); } public override void Write(Utf8JsonWriter writer, Handle value, JsonSerializerOptions options) diff --git a/dotnet/src/webdriver/BiDi/Json/Converters/InterceptConverter.cs b/dotnet/src/webdriver/BiDi/Json/Converters/InterceptConverter.cs index a72e6cfa96921..f2e56a4db3679 100644 --- a/dotnet/src/webdriver/BiDi/Json/Converters/InterceptConverter.cs +++ b/dotnet/src/webdriver/BiDi/Json/Converters/InterceptConverter.cs @@ -26,18 +26,12 @@ namespace OpenQA.Selenium.BiDi.Json.Converters; internal class InterceptConverter : JsonConverter { - private readonly BiDi _bidi; - - public InterceptConverter(BiDi bidi) - { - _bidi = bidi; - } - public override Intercept? Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) { var id = reader.GetString(); + var bidi = Broker.ThreadStaticBiDi ?? throw new InvalidOperationException("No BiDi set"); - return new Intercept(_bidi, id!); + return new Intercept(bidi, id!); } public override void Write(Utf8JsonWriter writer, Intercept value, JsonSerializerOptions options) diff --git a/dotnet/src/webdriver/BiDi/Json/Converters/InternalIdConverter.cs b/dotnet/src/webdriver/BiDi/Json/Converters/InternalIdConverter.cs index 6f14fa6571d64..eb74737ea51ae 100644 --- a/dotnet/src/webdriver/BiDi/Json/Converters/InternalIdConverter.cs +++ b/dotnet/src/webdriver/BiDi/Json/Converters/InternalIdConverter.cs @@ -26,18 +26,12 @@ namespace OpenQA.Selenium.BiDi.Json.Converters; internal class InternalIdConverter : JsonConverter { - private readonly BiDi _bidi; - - public InternalIdConverter(BiDi bidi) - { - _bidi = bidi; - } - public override InternalId? Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) { var id = reader.GetString(); + var bidi = Broker.ThreadStaticBiDi ?? throw new InvalidOperationException("No BiDi set"); - return new InternalId(_bidi, id!); + return new InternalId(bidi, id!); } public override void Write(Utf8JsonWriter writer, InternalId value, JsonSerializerOptions options) diff --git a/dotnet/src/webdriver/BiDi/Json/Converters/PreloadScriptConverter.cs b/dotnet/src/webdriver/BiDi/Json/Converters/PreloadScriptConverter.cs index 9a531f60f79ed..a39753a0cb212 100644 --- a/dotnet/src/webdriver/BiDi/Json/Converters/PreloadScriptConverter.cs +++ b/dotnet/src/webdriver/BiDi/Json/Converters/PreloadScriptConverter.cs @@ -26,18 +26,12 @@ namespace OpenQA.Selenium.BiDi.Json.Converters; internal class PreloadScriptConverter : JsonConverter { - private readonly BiDi _bidi; - - public PreloadScriptConverter(BiDi bidi) - { - _bidi = bidi; - } - public override PreloadScript? Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) { var id = reader.GetString(); + var bidi = Broker.ThreadStaticBiDi ?? throw new InvalidOperationException("No BiDi set"); - return new PreloadScript(_bidi, id!); + return new PreloadScript(bidi, id!); } public override void Write(Utf8JsonWriter writer, PreloadScript value, JsonSerializerOptions options) diff --git a/dotnet/src/webdriver/BiDi/Json/Converters/RealmConverter.cs b/dotnet/src/webdriver/BiDi/Json/Converters/RealmConverter.cs index 235c40b0363f4..526c03bdedb8f 100644 --- a/dotnet/src/webdriver/BiDi/Json/Converters/RealmConverter.cs +++ b/dotnet/src/webdriver/BiDi/Json/Converters/RealmConverter.cs @@ -26,18 +26,12 @@ namespace OpenQA.Selenium.BiDi.Json.Converters; internal class RealmConverter : JsonConverter { - private readonly BiDi _bidi; - - public RealmConverter(BiDi bidi) - { - _bidi = bidi; - } - public override Realm? Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) { var id = reader.GetString(); + var bidi = Broker.ThreadStaticBiDi ?? throw new InvalidOperationException("No BiDi set"); - return new Realm(_bidi, id!); + return new Realm(bidi, id!); } public override void Write(Utf8JsonWriter writer, Realm value, JsonSerializerOptions options) diff --git a/dotnet/src/webdriver/BiDi/Json/Converters/WebExtensionConverter.cs b/dotnet/src/webdriver/BiDi/Json/Converters/WebExtensionConverter.cs index ec3bc5e9cb7dd..651f0071be244 100644 --- a/dotnet/src/webdriver/BiDi/Json/Converters/WebExtensionConverter.cs +++ b/dotnet/src/webdriver/BiDi/Json/Converters/WebExtensionConverter.cs @@ -26,18 +26,12 @@ namespace OpenQA.Selenium.BiDi.Json.Converters; internal class WebExtensionConverter : JsonConverter { - private readonly BiDi _bidi; - - public WebExtensionConverter(BiDi bidi) - { - _bidi = bidi; - } - public override Extension? Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) { var id = reader.GetString(); + var bidi = Broker.ThreadStaticBiDi ?? throw new InvalidOperationException("No BiDi set"); - return new Extension(_bidi, id!); + return new Extension(bidi, id!); } public override void Write(Utf8JsonWriter writer, Extension value, JsonSerializerOptions options) diff --git a/dotnet/src/webdriver/BiDi/Network/Collector.cs b/dotnet/src/webdriver/BiDi/Network/Collector.cs index 0a1f56a5064a5..1f988a2cbd40f 100644 --- a/dotnet/src/webdriver/BiDi/Network/Collector.cs +++ b/dotnet/src/webdriver/BiDi/Network/Collector.cs @@ -17,11 +17,14 @@ // under the License. // +using OpenQA.Selenium.BiDi.Json.Converters; using System; +using System.Text.Json.Serialization; using System.Threading.Tasks; namespace OpenQA.Selenium.BiDi.Network; +[JsonConverter(typeof(CollectorConverter))] public sealed class Collector : IAsyncDisposable { private readonly BiDi _bidi; diff --git a/dotnet/src/webdriver/BiDi/Network/Intercept.cs b/dotnet/src/webdriver/BiDi/Network/Intercept.cs index c266f791efaa3..cf75de9fe4902 100644 --- a/dotnet/src/webdriver/BiDi/Network/Intercept.cs +++ b/dotnet/src/webdriver/BiDi/Network/Intercept.cs @@ -17,13 +17,16 @@ // under the License. // +using OpenQA.Selenium.BiDi.Json.Converters; using System; using System.Collections.Generic; using System.Linq; +using System.Text.Json.Serialization; using System.Threading.Tasks; namespace OpenQA.Selenium.BiDi.Network; +[JsonConverter(typeof(InterceptConverter))] public sealed class Intercept : IAsyncDisposable { private readonly BiDi _bidi; diff --git a/dotnet/src/webdriver/BiDi/Script/Handle.cs b/dotnet/src/webdriver/BiDi/Script/Handle.cs index 5b5e4f63ede08..f1ded67a260df 100644 --- a/dotnet/src/webdriver/BiDi/Script/Handle.cs +++ b/dotnet/src/webdriver/BiDi/Script/Handle.cs @@ -17,8 +17,12 @@ // under the License. // +using OpenQA.Selenium.BiDi.Json.Converters; +using System.Text.Json.Serialization; + namespace OpenQA.Selenium.BiDi.Script; +[JsonConverter(typeof(HandleConverter))] public sealed class Handle { private readonly BiDi _bidi; diff --git a/dotnet/src/webdriver/BiDi/Script/InternalId.cs b/dotnet/src/webdriver/BiDi/Script/InternalId.cs index 2914c77c99a0c..5c1a2bbd7bf00 100644 --- a/dotnet/src/webdriver/BiDi/Script/InternalId.cs +++ b/dotnet/src/webdriver/BiDi/Script/InternalId.cs @@ -17,8 +17,12 @@ // under the License. // +using OpenQA.Selenium.BiDi.Json.Converters; +using System.Text.Json.Serialization; + namespace OpenQA.Selenium.BiDi.Script; +[JsonConverter(typeof(InternalIdConverter))] public sealed class InternalId { readonly BiDi _bidi; diff --git a/dotnet/src/webdriver/BiDi/Script/PreloadScript.cs b/dotnet/src/webdriver/BiDi/Script/PreloadScript.cs index 428825305709c..b49787ade22ef 100644 --- a/dotnet/src/webdriver/BiDi/Script/PreloadScript.cs +++ b/dotnet/src/webdriver/BiDi/Script/PreloadScript.cs @@ -17,11 +17,14 @@ // under the License. // +using OpenQA.Selenium.BiDi.Json.Converters; using System; +using System.Text.Json.Serialization; using System.Threading.Tasks; namespace OpenQA.Selenium.BiDi.Script; +[JsonConverter(typeof(PreloadScriptConverter))] public sealed class PreloadScript : IAsyncDisposable { private readonly BiDi _bidi; diff --git a/dotnet/src/webdriver/BiDi/Script/Realm.cs b/dotnet/src/webdriver/BiDi/Script/Realm.cs index b3fd6f776e0c7..2506b544b67f2 100644 --- a/dotnet/src/webdriver/BiDi/Script/Realm.cs +++ b/dotnet/src/webdriver/BiDi/Script/Realm.cs @@ -17,8 +17,12 @@ // under the License. // +using OpenQA.Selenium.BiDi.Json.Converters; +using System.Text.Json.Serialization; + namespace OpenQA.Selenium.BiDi.Script; +[JsonConverter(typeof(RealmConverter))] public sealed class Realm { private readonly BiDi _bidi; diff --git a/dotnet/src/webdriver/BiDi/WebExtension/Extension.cs b/dotnet/src/webdriver/BiDi/WebExtension/Extension.cs index c19beb1579e70..375f15a00bdac 100644 --- a/dotnet/src/webdriver/BiDi/WebExtension/Extension.cs +++ b/dotnet/src/webdriver/BiDi/WebExtension/Extension.cs @@ -17,10 +17,13 @@ // under the License. // +using OpenQA.Selenium.BiDi.Json.Converters; +using System.Text.Json.Serialization; using System.Threading.Tasks; namespace OpenQA.Selenium.BiDi.WebExtension; +[JsonConverter(typeof(WebExtensionConverter))] public sealed class Extension { private readonly BiDi _bidi;