From 7b398a1a2f2612bc3c84aa885713c9f29aa7e449 Mon Sep 17 00:00:00 2001 From: Nikolay Borisenko <22616990+nvborisenko@users.noreply.github.com> Date: Wed, 3 Dec 2025 04:49:00 +0300 Subject: [PATCH 01/16] Remove stateless converters from json options --- dotnet/src/webdriver/BiDi/BiDi.cs | 20 +++++++++---------- .../webdriver/BiDi/Browser/BrowserModule.cs | 8 +------- .../src/webdriver/BiDi/Browser/UserContext.cs | 11 +++++----- .../BiDi/BrowsingContext/BrowsingContext.cs | 5 ++--- .../BrowsingContext/BrowsingContextModule.cs | 8 +------- .../BiDi/Emulation/EmulationModule.cs | 8 +------- .../src/webdriver/BiDi/Input/InputModule.cs | 8 +------- .../Converters/BrowserUserContextConverter.cs | 9 +-------- .../Converters/BrowsingContextConverter.cs | 9 +-------- .../Json/Converters/CollectorConverter.cs | 9 +-------- .../BiDi/Json/Converters/HandleConverter.cs | 9 +-------- .../Json/Converters/InterceptConverter.cs | 9 +-------- .../Json/Converters/InternalIdConverter.cs | 9 +-------- .../Json/Converters/PreloadScriptConverter.cs | 9 +-------- .../BiDi/Json/Converters/RealmConverter.cs | 9 +-------- .../Json/Converters/WebExtensionConverter.cs | 9 +-------- dotnet/src/webdriver/BiDi/Log/LogModule.cs | 8 +------- dotnet/src/webdriver/BiDi/Module.cs | 8 +------- .../src/webdriver/BiDi/Network/Collector.cs | 11 +++++----- .../src/webdriver/BiDi/Network/Intercept.cs | 17 ++++++++-------- .../webdriver/BiDi/Network/NetworkModule.cs | 8 +------- .../BiDi/Permissions/PermissionsModule.cs | 8 +------- dotnet/src/webdriver/BiDi/Script/Handle.cs | 10 ++++++---- .../src/webdriver/BiDi/Script/InternalId.cs | 10 ++++++---- .../webdriver/BiDi/Script/PreloadScript.cs | 11 +++++----- dotnet/src/webdriver/BiDi/Script/Realm.cs | 10 ++++++---- .../src/webdriver/BiDi/Script/ScriptModule.cs | 8 +------- .../webdriver/BiDi/Session/SessionModule.cs | 8 +------- .../webdriver/BiDi/Storage/StorageModule.cs | 8 +------- .../webdriver/BiDi/WebExtension/Extension.cs | 11 +++++----- .../BiDi/WebExtension/WebExtensionModule.cs | 8 +------- 31 files changed, 84 insertions(+), 209 deletions(-) diff --git a/dotnet/src/webdriver/BiDi/BiDi.cs b/dotnet/src/webdriver/BiDi/BiDi.cs index a6593ab29db86..6dc7451fe3283 100644 --- a/dotnet/src/webdriver/BiDi/BiDi.cs +++ b/dotnet/src/webdriver/BiDi/BiDi.cs @@ -85,7 +85,7 @@ public async ValueTask DisposeAsync() public T AsModule() where T : Module, new() { - return (T)_modules.GetOrAdd(typeof(T), _ => Module.Create(this, Broker, GetJsonOptions())); + return (T)_modules.GetOrAdd(typeof(T), _ => Module.Create(this, Broker)); } private Broker Broker { get; } @@ -103,16 +103,16 @@ 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 BrowsingContextConverter(), + new BrowserUserContextConverter(), + new CollectorConverter(), + new InterceptConverter(), + new HandleConverter(), + new InternalIdConverter(), + new PreloadScriptConverter(), + new RealmConverter(), new DateTimeOffsetConverter(), - new WebExtensionConverter(this), + new WebExtensionConverter(), } }; } diff --git a/dotnet/src/webdriver/BiDi/Browser/BrowserModule.cs b/dotnet/src/webdriver/BiDi/Browser/BrowserModule.cs index a1427163d6e24..5c84820a93c7c 100644 --- a/dotnet/src/webdriver/BiDi/Browser/BrowserModule.cs +++ b/dotnet/src/webdriver/BiDi/Browser/BrowserModule.cs @@ -17,7 +17,6 @@ // under the License. // -using System.Text.Json; using System.Text.Json.Serialization; using System.Threading.Tasks; @@ -25,7 +24,7 @@ namespace OpenQA.Selenium.BiDi.Browser; public sealed class BrowserModule : Module { - private BrowserJsonSerializerContext _jsonContext = null!; + private static readonly BrowserJsonSerializerContext _jsonContext = BrowserJsonSerializerContext.Default; public async Task CloseAsync(CloseOptions? options = null) { @@ -77,11 +76,6 @@ public async Task SetDownloadBehaviorDeniedAsync(SetD return await Broker.ExecuteCommandAsync(new SetDownloadBehaviorCommand(@params), options, _jsonContext.SetDownloadBehaviorCommand, _jsonContext.SetDownloadBehaviorResult).ConfigureAwait(false); } - - protected override void Initialize(JsonSerializerOptions options) - { - _jsonContext = new BrowserJsonSerializerContext(options); - } } [JsonSerializable(typeof(CloseCommand))] diff --git a/dotnet/src/webdriver/BiDi/Browser/UserContext.cs b/dotnet/src/webdriver/BiDi/Browser/UserContext.cs index 46066271be9e1..3c0ed98242f62 100644 --- a/dotnet/src/webdriver/BiDi/Browser/UserContext.cs +++ b/dotnet/src/webdriver/BiDi/Browser/UserContext.cs @@ -18,25 +18,26 @@ // using System; +using System.Text.Json.Serialization; using System.Threading.Tasks; namespace OpenQA.Selenium.BiDi.Browser; public sealed class UserContext : IEquatable, IAsyncDisposable { - private readonly BiDi _bidi; - - internal UserContext(BiDi bidi, string id) + internal UserContext(string id) { - _bidi = bidi; Id = id; } internal string Id { get; } + [JsonIgnore] + public BiDi BiDi { get; internal set; } + public Task RemoveAsync() { - return _bidi.Browser.RemoveUserContextAsync(this); + return BiDi.Browser.RemoveUserContextAsync(this); } public async ValueTask DisposeAsync() diff --git a/dotnet/src/webdriver/BiDi/BrowsingContext/BrowsingContext.cs b/dotnet/src/webdriver/BiDi/BrowsingContext/BrowsingContext.cs index 24fdc57b0b1bd..41a36bf27fb8e 100644 --- a/dotnet/src/webdriver/BiDi/BrowsingContext/BrowsingContext.cs +++ b/dotnet/src/webdriver/BiDi/BrowsingContext/BrowsingContext.cs @@ -26,9 +26,8 @@ namespace OpenQA.Selenium.BiDi.BrowsingContext; public sealed class BrowsingContext { - internal BrowsingContext(BiDi bidi, string id) + internal BrowsingContext(string id) { - BiDi = bidi; Id = id; } @@ -41,7 +40,7 @@ internal BrowsingContext(BiDi bidi, string id) internal string Id { get; } [JsonIgnore] - public BiDi BiDi { get; } + public BiDi BiDi { get; internal set; } [JsonIgnore] public BrowsingContextLogModule Log => _logModule ?? Interlocked.CompareExchange(ref _logModule, new BrowsingContextLogModule(this, BiDi.Log), null) ?? _logModule; diff --git a/dotnet/src/webdriver/BiDi/BrowsingContext/BrowsingContextModule.cs b/dotnet/src/webdriver/BiDi/BrowsingContext/BrowsingContextModule.cs index 1e6b1ca4e3d70..2c63a1c1acc58 100644 --- a/dotnet/src/webdriver/BiDi/BrowsingContext/BrowsingContextModule.cs +++ b/dotnet/src/webdriver/BiDi/BrowsingContext/BrowsingContextModule.cs @@ -18,7 +18,6 @@ // using System; -using System.Text.Json; using System.Text.Json.Serialization; using System.Threading.Tasks; @@ -26,7 +25,7 @@ namespace OpenQA.Selenium.BiDi.BrowsingContext; public sealed class BrowsingContextModule : Module { - private BrowsingContextJsonSerializerContext _jsonContext = null!; + private static readonly BrowsingContextJsonSerializerContext _jsonContext = BrowsingContextJsonSerializerContext.Default; public async Task CreateAsync(ContextType type, CreateOptions? options = null) { @@ -251,11 +250,6 @@ public async Task OnUserPromptClosedAsync(Action -using System.Text.Json; using System.Text.Json.Serialization; using System.Threading.Tasks; @@ -25,7 +24,7 @@ namespace OpenQA.Selenium.BiDi.Emulation; public sealed class EmulationModule : Module { - private EmulationJsonSerializerContext _jsonContext = null!; + private static readonly EmulationJsonSerializerContext _jsonContext = EmulationJsonSerializerContext.Default; public async Task SetTimezoneOverrideAsync(string? timezone, SetTimezoneOverrideOptions? options = null) { @@ -91,11 +90,6 @@ public async Task SetGeolocationPositionErrorOverr return await Broker.ExecuteCommandAsync(new SetGeolocationOverrideCommand(@params), options, _jsonContext.SetGeolocationOverrideCommand, _jsonContext.SetGeolocationOverrideResult).ConfigureAwait(false); } - - protected override void Initialize(JsonSerializerOptions options) - { - _jsonContext = new EmulationJsonSerializerContext(options); - } } [JsonSerializable(typeof(SetTimezoneOverrideCommand))] diff --git a/dotnet/src/webdriver/BiDi/Input/InputModule.cs b/dotnet/src/webdriver/BiDi/Input/InputModule.cs index fb6ded16381d4..293534443e712 100644 --- a/dotnet/src/webdriver/BiDi/Input/InputModule.cs +++ b/dotnet/src/webdriver/BiDi/Input/InputModule.cs @@ -18,7 +18,6 @@ // using System.Collections.Generic; -using System.Text.Json; using System.Text.Json.Serialization; using System.Threading.Tasks; @@ -26,7 +25,7 @@ namespace OpenQA.Selenium.BiDi.Input; public sealed class InputModule : Module { - private InputJsonSerializerContext _jsonContext = null!; + private static readonly InputJsonSerializerContext _jsonContext = InputJsonSerializerContext.Default; public async Task PerformActionsAsync(BrowsingContext.BrowsingContext context, IEnumerable actions, PerformActionsOptions? options = null) { @@ -48,11 +47,6 @@ public async Task SetFilesAsync(BrowsingContext.BrowsingContext return await Broker.ExecuteCommandAsync(new SetFilesCommand(@params), options, _jsonContext.SetFilesCommand, _jsonContext.SetFilesResult).ConfigureAwait(false); } - - protected override void Initialize(JsonSerializerOptions options) - { - _jsonContext = new InputJsonSerializerContext(options); - } } [JsonSerializable(typeof(PerformActionsCommand))] diff --git a/dotnet/src/webdriver/BiDi/Json/Converters/BrowserUserContextConverter.cs b/dotnet/src/webdriver/BiDi/Json/Converters/BrowserUserContextConverter.cs index e660c9843f086..7c0576a25303e 100644 --- a/dotnet/src/webdriver/BiDi/Json/Converters/BrowserUserContextConverter.cs +++ b/dotnet/src/webdriver/BiDi/Json/Converters/BrowserUserContextConverter.cs @@ -26,18 +26,11 @@ 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(); - return new UserContext(_bidi, id!); + return new UserContext(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..38a852aa70172 100644 --- a/dotnet/src/webdriver/BiDi/Json/Converters/BrowsingContextConverter.cs +++ b/dotnet/src/webdriver/BiDi/Json/Converters/BrowsingContextConverter.cs @@ -25,18 +25,11 @@ 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(); - return new BrowsingContext.BrowsingContext(_bidi, id!); + return new BrowsingContext.BrowsingContext(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..87209845e93f1 100644 --- a/dotnet/src/webdriver/BiDi/Json/Converters/CollectorConverter.cs +++ b/dotnet/src/webdriver/BiDi/Json/Converters/CollectorConverter.cs @@ -26,18 +26,11 @@ 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(); - return new Collector(_bidi, id!); + return new Collector(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..38e15e516a274 100644 --- a/dotnet/src/webdriver/BiDi/Json/Converters/HandleConverter.cs +++ b/dotnet/src/webdriver/BiDi/Json/Converters/HandleConverter.cs @@ -26,18 +26,11 @@ 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(); - return new Handle(_bidi, id!); + return new Handle(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..f4bd6f4a34650 100644 --- a/dotnet/src/webdriver/BiDi/Json/Converters/InterceptConverter.cs +++ b/dotnet/src/webdriver/BiDi/Json/Converters/InterceptConverter.cs @@ -26,18 +26,11 @@ 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(); - return new Intercept(_bidi, id!); + return new Intercept(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..98a7ca5d5c575 100644 --- a/dotnet/src/webdriver/BiDi/Json/Converters/InternalIdConverter.cs +++ b/dotnet/src/webdriver/BiDi/Json/Converters/InternalIdConverter.cs @@ -26,18 +26,11 @@ 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(); - return new InternalId(_bidi, id!); + return new InternalId(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..feae08b69321c 100644 --- a/dotnet/src/webdriver/BiDi/Json/Converters/PreloadScriptConverter.cs +++ b/dotnet/src/webdriver/BiDi/Json/Converters/PreloadScriptConverter.cs @@ -26,18 +26,11 @@ 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(); - return new PreloadScript(_bidi, id!); + return new PreloadScript(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..7b8c28eb2eba7 100644 --- a/dotnet/src/webdriver/BiDi/Json/Converters/RealmConverter.cs +++ b/dotnet/src/webdriver/BiDi/Json/Converters/RealmConverter.cs @@ -26,18 +26,11 @@ 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(); - return new Realm(_bidi, id!); + return new Realm(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..0c6a7f4cfde73 100644 --- a/dotnet/src/webdriver/BiDi/Json/Converters/WebExtensionConverter.cs +++ b/dotnet/src/webdriver/BiDi/Json/Converters/WebExtensionConverter.cs @@ -26,18 +26,11 @@ 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(); - return new Extension(_bidi, id!); + return new Extension(id!); } public override void Write(Utf8JsonWriter writer, Extension value, JsonSerializerOptions options) diff --git a/dotnet/src/webdriver/BiDi/Log/LogModule.cs b/dotnet/src/webdriver/BiDi/Log/LogModule.cs index 34ea0e1d66c4c..34b648d4f7254 100644 --- a/dotnet/src/webdriver/BiDi/Log/LogModule.cs +++ b/dotnet/src/webdriver/BiDi/Log/LogModule.cs @@ -18,7 +18,6 @@ // using System; -using System.Text.Json; using System.Text.Json.Serialization; using System.Threading.Tasks; @@ -26,7 +25,7 @@ namespace OpenQA.Selenium.BiDi.Log; public sealed class LogModule : Module { - private LogJsonSerializerContext _jsonContext = null!; + private static readonly LogJsonSerializerContext _jsonContext = LogJsonSerializerContext.Default; public async Task OnEntryAddedAsync(Func handler, SubscriptionOptions? options = null) { @@ -37,11 +36,6 @@ public async Task OnEntryAddedAsync(Action handler, Subs { return await Broker.SubscribeAsync("log.entryAdded", handler, options, _jsonContext.LogEntry).ConfigureAwait(false); } - - protected override void Initialize(JsonSerializerOptions options) - { - _jsonContext = new LogJsonSerializerContext(options); - } } #region https://github.com/dotnet/runtime/issues/72604 Script.RemoteValue type dependency diff --git a/dotnet/src/webdriver/BiDi/Module.cs b/dotnet/src/webdriver/BiDi/Module.cs index 4e90c2db7df67..e8c1a27efe6a7 100644 --- a/dotnet/src/webdriver/BiDi/Module.cs +++ b/dotnet/src/webdriver/BiDi/Module.cs @@ -17,8 +17,6 @@ // under the License. // -using System.Text.Json; - namespace OpenQA.Selenium.BiDi; public abstract class Module @@ -27,9 +25,7 @@ public abstract class Module protected Broker Broker { get; private set; } = null!; - protected abstract void Initialize(JsonSerializerOptions options); - - internal static TModule Create(BiDi bidi, Broker broker, JsonSerializerOptions jsonSerializerOptions) + internal static TModule Create(BiDi bidi, Broker broker) where TModule : Module, new() { TModule module = new() @@ -38,8 +34,6 @@ internal static TModule Create(BiDi bidi, Broker broker, JsonSerializer Broker = broker }; - module.Initialize(jsonSerializerOptions); - return module; } } diff --git a/dotnet/src/webdriver/BiDi/Network/Collector.cs b/dotnet/src/webdriver/BiDi/Network/Collector.cs index 0a1f56a5064a5..6239c25fc3a17 100644 --- a/dotnet/src/webdriver/BiDi/Network/Collector.cs +++ b/dotnet/src/webdriver/BiDi/Network/Collector.cs @@ -18,25 +18,26 @@ // using System; +using System.Text.Json.Serialization; using System.Threading.Tasks; namespace OpenQA.Selenium.BiDi.Network; public sealed class Collector : IAsyncDisposable { - private readonly BiDi _bidi; - - internal Collector(BiDi bidi, string id) + internal Collector(string id) { - _bidi = bidi; Id = id; } internal string Id { get; } + [JsonIgnore] + public BiDi BiDi { get; internal set; } + public async Task RemoveAsync() { - await _bidi.Network.RemoveDataCollectorAsync(this).ConfigureAwait(false); + await BiDi.Network.RemoveDataCollectorAsync(this).ConfigureAwait(false); } public async ValueTask DisposeAsync() diff --git a/dotnet/src/webdriver/BiDi/Network/Intercept.cs b/dotnet/src/webdriver/BiDi/Network/Intercept.cs index c266f791efaa3..2b5ee6510b52d 100644 --- a/dotnet/src/webdriver/BiDi/Network/Intercept.cs +++ b/dotnet/src/webdriver/BiDi/Network/Intercept.cs @@ -20,29 +20,30 @@ using System; using System.Collections.Generic; using System.Linq; +using System.Text.Json.Serialization; using System.Threading.Tasks; namespace OpenQA.Selenium.BiDi.Network; public sealed class Intercept : IAsyncDisposable { - private readonly BiDi _bidi; - - internal Intercept(BiDi bidi, string id) + internal Intercept(string id) { - _bidi = bidi; Id = id; } internal string Id { get; } + [JsonIgnore] + public BiDi BiDi { get; internal set; } + IList OnBeforeRequestSentSubscriptions { get; } = []; IList OnResponseStartedSubscriptions { get; } = []; IList OnAuthRequiredSubscriptions { get; } = []; public async Task RemoveAsync() { - await _bidi.Network.RemoveInterceptAsync(this).ConfigureAwait(false); + await BiDi.Network.RemoveInterceptAsync(this).ConfigureAwait(false); foreach (var subscription in OnBeforeRequestSentSubscriptions) { @@ -62,21 +63,21 @@ public async Task RemoveAsync() public async Task OnBeforeRequestSentAsync(Func handler, SubscriptionOptions? options = null) { - var subscription = await _bidi.Network.OnBeforeRequestSentAsync(async args => await Filter(args, handler), options).ConfigureAwait(false); + var subscription = await BiDi.Network.OnBeforeRequestSentAsync(async args => await Filter(args, handler), options).ConfigureAwait(false); OnBeforeRequestSentSubscriptions.Add(subscription); } public async Task OnResponseStartedAsync(Func handler, SubscriptionOptions? options = null) { - var subscription = await _bidi.Network.OnResponseStartedAsync(async args => await Filter(args, handler), options).ConfigureAwait(false); + var subscription = await BiDi.Network.OnResponseStartedAsync(async args => await Filter(args, handler), options).ConfigureAwait(false); OnResponseStartedSubscriptions.Add(subscription); } public async Task OnAuthRequiredAsync(Func handler, SubscriptionOptions? options = null) { - var subscription = await _bidi.Network.OnAuthRequiredAsync(async args => await Filter(args, handler), options).ConfigureAwait(false); + var subscription = await BiDi.Network.OnAuthRequiredAsync(async args => await Filter(args, handler), options).ConfigureAwait(false); OnAuthRequiredSubscriptions.Add(subscription); } diff --git a/dotnet/src/webdriver/BiDi/Network/NetworkModule.cs b/dotnet/src/webdriver/BiDi/Network/NetworkModule.cs index 74b874078e237..d8ad30809e45e 100644 --- a/dotnet/src/webdriver/BiDi/Network/NetworkModule.cs +++ b/dotnet/src/webdriver/BiDi/Network/NetworkModule.cs @@ -19,7 +19,6 @@ using System; using System.Collections.Generic; -using System.Text.Json; using System.Text.Json.Serialization; using System.Threading.Tasks; @@ -27,7 +26,7 @@ namespace OpenQA.Selenium.BiDi.Network; public sealed partial class NetworkModule : Module { - private NetworkJsonSerializerContext _jsonContext = null!; + private static readonly NetworkJsonSerializerContext _jsonContext = NetworkJsonSerializerContext.Default; public async Task AddDataCollectorAsync(IEnumerable DataTypes, int MaxEncodedDataSize, AddDataCollectorOptions? options = null) { @@ -176,11 +175,6 @@ public async Task OnAuthRequiredAsync(Action using OpenQA.Selenium.BiDi.Permissions; -using System.Text.Json; using System.Text.Json.Serialization; using System.Threading.Tasks; @@ -26,7 +25,7 @@ namespace OpenQA.Selenium.BiDi.Extensions.Permissions; public class PermissionsModule : Module { - private PermissionsJsonSerializerContext _jsonContext = null!; + private static readonly PermissionsJsonSerializerContext _jsonContext = PermissionsJsonSerializerContext.Default; public async Task SetPermissionAsync(PermissionDescriptor desriptor, PermissionState state, string origin, SetPermissionOptions? options = null) { @@ -34,11 +33,6 @@ public async Task SetPermissionAsync(PermissionDescriptor d return await Broker.ExecuteCommandAsync(new SetPermissionCommand(@params), options, _jsonContext.SetPermissionCommand, _jsonContext.SetPermissionResult).ConfigureAwait(false); } - - protected override void Initialize(JsonSerializerOptions options) - { - _jsonContext = new PermissionsJsonSerializerContext(options); - } } [JsonSerializable(typeof(SetPermissionCommand))] diff --git a/dotnet/src/webdriver/BiDi/Script/Handle.cs b/dotnet/src/webdriver/BiDi/Script/Handle.cs index 5b5e4f63ede08..17a3a70c8be27 100644 --- a/dotnet/src/webdriver/BiDi/Script/Handle.cs +++ b/dotnet/src/webdriver/BiDi/Script/Handle.cs @@ -17,17 +17,19 @@ // under the License. // +using System.Text.Json.Serialization; + namespace OpenQA.Selenium.BiDi.Script; public sealed class Handle { - private readonly BiDi _bidi; - - public Handle(BiDi bidi, string id) + public Handle(string id) { - _bidi = bidi; Id = id; } public string Id { get; } + + [JsonIgnore] + public BiDi BiDi { get; internal set; } } diff --git a/dotnet/src/webdriver/BiDi/Script/InternalId.cs b/dotnet/src/webdriver/BiDi/Script/InternalId.cs index 2914c77c99a0c..31d276236ec20 100644 --- a/dotnet/src/webdriver/BiDi/Script/InternalId.cs +++ b/dotnet/src/webdriver/BiDi/Script/InternalId.cs @@ -17,17 +17,19 @@ // under the License. // +using System.Text.Json.Serialization; + namespace OpenQA.Selenium.BiDi.Script; public sealed class InternalId { - readonly BiDi _bidi; - - public InternalId(BiDi bidi, string id) + public InternalId(string id) { - _bidi = bidi; Id = id; } public string Id { get; } + + [JsonIgnore] + public BiDi BiDi { get; internal set; } } diff --git a/dotnet/src/webdriver/BiDi/Script/PreloadScript.cs b/dotnet/src/webdriver/BiDi/Script/PreloadScript.cs index 428825305709c..f65053eb8b0c2 100644 --- a/dotnet/src/webdriver/BiDi/Script/PreloadScript.cs +++ b/dotnet/src/webdriver/BiDi/Script/PreloadScript.cs @@ -18,25 +18,26 @@ // using System; +using System.Text.Json.Serialization; using System.Threading.Tasks; namespace OpenQA.Selenium.BiDi.Script; public sealed class PreloadScript : IAsyncDisposable { - private readonly BiDi _bidi; - - public PreloadScript(BiDi bidi, string id) + internal PreloadScript(string id) { - _bidi = bidi; Id = id; } public string Id { get; } + [JsonIgnore] + public BiDi BiDi { get; internal set; } + public Task RemoveAsync() { - return _bidi.Script.RemovePreloadScriptAsync(this); + return BiDi.Script.RemovePreloadScriptAsync(this); } public async ValueTask DisposeAsync() diff --git a/dotnet/src/webdriver/BiDi/Script/Realm.cs b/dotnet/src/webdriver/BiDi/Script/Realm.cs index b3fd6f776e0c7..43fcc24df8571 100644 --- a/dotnet/src/webdriver/BiDi/Script/Realm.cs +++ b/dotnet/src/webdriver/BiDi/Script/Realm.cs @@ -17,17 +17,19 @@ // under the License. // +using System.Text.Json.Serialization; + namespace OpenQA.Selenium.BiDi.Script; public sealed class Realm { - private readonly BiDi _bidi; - - public Realm(BiDi bidi, string id) + public Realm(string id) { - _bidi = bidi; Id = id; } public string Id { get; } + + [JsonIgnore] + public BiDi BiDi { get; internal set; } } diff --git a/dotnet/src/webdriver/BiDi/Script/ScriptModule.cs b/dotnet/src/webdriver/BiDi/Script/ScriptModule.cs index bd1354decc6e8..0bd015eeb49a5 100644 --- a/dotnet/src/webdriver/BiDi/Script/ScriptModule.cs +++ b/dotnet/src/webdriver/BiDi/Script/ScriptModule.cs @@ -20,7 +20,6 @@ using System; using System.Collections.Generic; using System.Diagnostics.CodeAnalysis; -using System.Text.Json; using System.Text.Json.Serialization; using System.Threading.Tasks; @@ -28,7 +27,7 @@ namespace OpenQA.Selenium.BiDi.Script; public sealed class ScriptModule : Module { - private ScriptJsonSerializerContext _jsonContext = null!; + private static readonly ScriptJsonSerializerContext _jsonContext = ScriptJsonSerializerContext.Default; public async Task EvaluateAsync([StringSyntax(StringSyntaxConstants.JavaScript)] string expression, bool awaitPromise, Target target, EvaluateOptions? options = null) { @@ -115,11 +114,6 @@ public async Task OnRealmDestroyedAsync(Action using System.Collections.Generic; -using System.Text.Json; using System.Text.Json.Serialization; using System.Threading.Tasks; @@ -26,7 +25,7 @@ namespace OpenQA.Selenium.BiDi.Session; internal sealed class SessionModule : Module { - private SessionJsonSerializerContext _jsonContext = null!; + private static readonly SessionJsonSerializerContext _jsonContext = SessionJsonSerializerContext.Default; public async Task StatusAsync(StatusOptions? options = null) { @@ -58,11 +57,6 @@ public async Task EndAsync(EndOptions? options = null) { return await Broker.ExecuteCommandAsync(new EndCommand(), options, _jsonContext.EndCommand, _jsonContext.EndResult).ConfigureAwait(false); } - - protected override void Initialize(JsonSerializerOptions options) - { - _jsonContext = new SessionJsonSerializerContext(options); - } } [JsonSerializable(typeof(StatusCommand))] diff --git a/dotnet/src/webdriver/BiDi/Storage/StorageModule.cs b/dotnet/src/webdriver/BiDi/Storage/StorageModule.cs index d2ef4c263f515..373873b6be19b 100644 --- a/dotnet/src/webdriver/BiDi/Storage/StorageModule.cs +++ b/dotnet/src/webdriver/BiDi/Storage/StorageModule.cs @@ -17,7 +17,6 @@ // under the License. // -using System.Text.Json; using System.Text.Json.Serialization; using System.Threading.Tasks; @@ -25,7 +24,7 @@ namespace OpenQA.Selenium.BiDi.Storage; public sealed class StorageModule : Module { - private StorageJsonSerializerContext _jsonContext = null!; + private static readonly StorageJsonSerializerContext _jsonContext = StorageJsonSerializerContext.Default; public async Task GetCookiesAsync(GetCookiesOptions? options = null) { @@ -47,11 +46,6 @@ public async Task SetCookieAsync(PartialCookie cookie, SetCooki return await Broker.ExecuteCommandAsync(new SetCookieCommand(@params), options, _jsonContext.SetCookieCommand, _jsonContext.SetCookieResult).ConfigureAwait(false); } - - protected override void Initialize(JsonSerializerOptions options) - { - _jsonContext = new StorageJsonSerializerContext(options); - } } [JsonSerializable(typeof(GetCookiesCommand))] diff --git a/dotnet/src/webdriver/BiDi/WebExtension/Extension.cs b/dotnet/src/webdriver/BiDi/WebExtension/Extension.cs index c19beb1579e70..db19136a2fc2e 100644 --- a/dotnet/src/webdriver/BiDi/WebExtension/Extension.cs +++ b/dotnet/src/webdriver/BiDi/WebExtension/Extension.cs @@ -17,24 +17,25 @@ // under the License. // +using System.Text.Json.Serialization; using System.Threading.Tasks; namespace OpenQA.Selenium.BiDi.WebExtension; public sealed class Extension { - private readonly BiDi _bidi; - - public Extension(BiDi bidi, string id) + internal Extension(string id) { - _bidi = bidi; Id = id; } internal string Id { get; } + [JsonIgnore] + public BiDi BiDi { get; internal set; } + public Task UninstallAsync(UninstallOptions? options = null) { - return _bidi.WebExtension.UninstallAsync(this, options); + return BiDi.WebExtension.UninstallAsync(this, options); } } diff --git a/dotnet/src/webdriver/BiDi/WebExtension/WebExtensionModule.cs b/dotnet/src/webdriver/BiDi/WebExtension/WebExtensionModule.cs index 86cfea9d1f9a5..38f13958530db 100644 --- a/dotnet/src/webdriver/BiDi/WebExtension/WebExtensionModule.cs +++ b/dotnet/src/webdriver/BiDi/WebExtension/WebExtensionModule.cs @@ -17,7 +17,6 @@ // under the License. // -using System.Text.Json; using System.Text.Json.Serialization; using System.Threading.Tasks; @@ -25,7 +24,7 @@ namespace OpenQA.Selenium.BiDi.WebExtension; public sealed class WebExtensionModule : Module { - private WebExtensionJsonSerializerContext _jsonContext = null!; + private static readonly WebExtensionJsonSerializerContext _jsonContext = WebExtensionJsonSerializerContext.Default; public async Task InstallAsync(ExtensionData extensionData, InstallOptions? options = null) { @@ -40,11 +39,6 @@ public async Task UninstallAsync(Extension extension, Uninstall return await Broker.ExecuteCommandAsync(new UninstallCommand(@params), options, _jsonContext.UninstallCommand, _jsonContext.UninstallResult).ConfigureAwait(false); } - - protected override void Initialize(JsonSerializerOptions options) - { - _jsonContext = new WebExtensionJsonSerializerContext(options); - } } [JsonSerializable(typeof(InstallCommand))] From b0f5e1e0f658f6da88e5c27b229d37b52130f6ff Mon Sep 17 00:00:00 2001 From: Nikolay Borisenko <22616990+nvborisenko@users.noreply.github.com> Date: Wed, 3 Dec 2025 05:24:40 +0300 Subject: [PATCH 02/16] Generated options --- dotnet/src/webdriver/BiDi/BiDi.cs | 24 +++++++++---------- .../webdriver/BiDi/Browser/BrowserModule.cs | 9 +++++++ .../src/webdriver/BiDi/Browser/UserContext.cs | 2 ++ .../BiDi/BrowsingContext/BrowsingContext.cs | 2 ++ .../BrowsingContext/BrowsingContextModule.cs | 9 +++++++ .../BiDi/Emulation/EmulationModule.cs | 9 +++++++ .../src/webdriver/BiDi/Input/InputModule.cs | 9 +++++++ dotnet/src/webdriver/BiDi/Log/LogModule.cs | 9 +++++++ .../src/webdriver/BiDi/Network/Collector.cs | 2 ++ .../src/webdriver/BiDi/Network/Intercept.cs | 2 ++ .../webdriver/BiDi/Network/NetworkModule.cs | 9 +++++++ .../BiDi/Permissions/PermissionsModule.cs | 9 +++++++ dotnet/src/webdriver/BiDi/Script/Handle.cs | 2 ++ .../src/webdriver/BiDi/Script/InternalId.cs | 2 ++ .../webdriver/BiDi/Script/PreloadScript.cs | 2 ++ dotnet/src/webdriver/BiDi/Script/Realm.cs | 2 ++ .../src/webdriver/BiDi/Script/ScriptModule.cs | 9 +++++++ .../webdriver/BiDi/Session/SessionModule.cs | 9 +++++++ .../webdriver/BiDi/Storage/StorageModule.cs | 9 +++++++ .../webdriver/BiDi/WebExtension/Extension.cs | 2 ++ .../BiDi/WebExtension/WebExtensionModule.cs | 9 +++++++ 21 files changed, 129 insertions(+), 12 deletions(-) diff --git a/dotnet/src/webdriver/BiDi/BiDi.cs b/dotnet/src/webdriver/BiDi/BiDi.cs index 6dc7451fe3283..c3a838f10d14e 100644 --- a/dotnet/src/webdriver/BiDi/BiDi.cs +++ b/dotnet/src/webdriver/BiDi/BiDi.cs @@ -94,25 +94,25 @@ private JsonSerializerOptions GetJsonOptions() { return new JsonSerializerOptions { - PropertyNameCaseInsensitive = true, - PropertyNamingPolicy = JsonNamingPolicy.CamelCase, - DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull, + //PropertyNameCaseInsensitive = true, + //PropertyNamingPolicy = JsonNamingPolicy.CamelCase, + //DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull, // BiDi returns special numbers such as "NaN" as strings // Additionally, -0 is returned as a string "-0" NumberHandling = JsonNumberHandling.AllowNamedFloatingPointLiterals | JsonNumberHandling.AllowReadingFromString, Converters = { - new BrowsingContextConverter(), - new BrowserUserContextConverter(), - new CollectorConverter(), - new InterceptConverter(), - new HandleConverter(), - new InternalIdConverter(), - new PreloadScriptConverter(), - new RealmConverter(), + //new BrowsingContextConverter(), + //new BrowserUserContextConverter(), + //new CollectorConverter(), + //new InterceptConverter(), + //new HandleConverter(), + //new InternalIdConverter(), + //new PreloadScriptConverter(), + //new RealmConverter(), new DateTimeOffsetConverter(), - new WebExtensionConverter(), + //new WebExtensionConverter(), } }; } diff --git a/dotnet/src/webdriver/BiDi/Browser/BrowserModule.cs b/dotnet/src/webdriver/BiDi/Browser/BrowserModule.cs index 5c84820a93c7c..c043bbaabd5e2 100644 --- a/dotnet/src/webdriver/BiDi/Browser/BrowserModule.cs +++ b/dotnet/src/webdriver/BiDi/Browser/BrowserModule.cs @@ -17,6 +17,7 @@ // under the License. // +using OpenQA.Selenium.BiDi.Json.Converters; using System.Text.Json.Serialization; using System.Threading.Tasks; @@ -90,4 +91,12 @@ public async Task SetDownloadBehaviorDeniedAsync(SetD [JsonSerializable(typeof(GetClientWindowsResult))] [JsonSerializable(typeof(SetDownloadBehaviorCommand))] [JsonSerializable(typeof(SetDownloadBehaviorResult))] + +#pragma warning disable CS3016 // Arrays as attribute arguments is not CLS-compliant +[JsonSourceGenerationOptions( + PropertyNameCaseInsensitive = true, + DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull, + PropertyNamingPolicy = JsonKnownNamingPolicy.CamelCase, + Converters = [typeof(DateTimeOffsetConverter)])] +#pragma warning restore CS3016 // Arrays as attribute arguments is not CLS-compliant internal partial class BrowserJsonSerializerContext : JsonSerializerContext; diff --git a/dotnet/src/webdriver/BiDi/Browser/UserContext.cs b/dotnet/src/webdriver/BiDi/Browser/UserContext.cs index 3c0ed98242f62..11624c981e4e8 100644 --- a/dotnet/src/webdriver/BiDi/Browser/UserContext.cs +++ b/dotnet/src/webdriver/BiDi/Browser/UserContext.cs @@ -17,12 +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 { internal UserContext(string id) diff --git a/dotnet/src/webdriver/BiDi/BrowsingContext/BrowsingContext.cs b/dotnet/src/webdriver/BiDi/BrowsingContext/BrowsingContext.cs index 41a36bf27fb8e..6b1a14ebdeb2f 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(string id) diff --git a/dotnet/src/webdriver/BiDi/BrowsingContext/BrowsingContextModule.cs b/dotnet/src/webdriver/BiDi/BrowsingContext/BrowsingContextModule.cs index 2c63a1c1acc58..b922e1cfa6faa 100644 --- a/dotnet/src/webdriver/BiDi/BrowsingContext/BrowsingContextModule.cs +++ b/dotnet/src/webdriver/BiDi/BrowsingContext/BrowsingContextModule.cs @@ -17,6 +17,7 @@ // under the License. // +using OpenQA.Selenium.BiDi.Json.Converters; using System; using System.Text.Json.Serialization; using System.Threading.Tasks; @@ -286,4 +287,12 @@ public async Task OnUserPromptClosedAsync(Action +using OpenQA.Selenium.BiDi.Json.Converters; using System.Text.Json.Serialization; using System.Threading.Tasks; @@ -106,4 +107,12 @@ public async Task SetGeolocationPositionErrorOverr [JsonSerializable(typeof(SetScreenOrientationOverrideResult))] [JsonSerializable(typeof(SetGeolocationOverrideCommand))] [JsonSerializable(typeof(SetGeolocationOverrideResult))] + +#pragma warning disable CS3016 // Arrays as attribute arguments is not CLS-compliant +[JsonSourceGenerationOptions( + PropertyNameCaseInsensitive = true, + DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull, + PropertyNamingPolicy = JsonKnownNamingPolicy.CamelCase, + Converters = [typeof(DateTimeOffsetConverter)])] +#pragma warning restore CS3016 // Arrays as attribute arguments is not CLS-compliant internal partial class EmulationJsonSerializerContext : JsonSerializerContext; diff --git a/dotnet/src/webdriver/BiDi/Input/InputModule.cs b/dotnet/src/webdriver/BiDi/Input/InputModule.cs index 293534443e712..293e33416cdd5 100644 --- a/dotnet/src/webdriver/BiDi/Input/InputModule.cs +++ b/dotnet/src/webdriver/BiDi/Input/InputModule.cs @@ -17,6 +17,7 @@ // under the License. // +using OpenQA.Selenium.BiDi.Json.Converters; using System.Collections.Generic; using System.Text.Json.Serialization; using System.Threading.Tasks; @@ -59,4 +60,12 @@ public async Task SetFilesAsync(BrowsingContext.BrowsingContext [JsonSerializable(typeof(IEnumerable))] [JsonSerializable(typeof(IEnumerable))] [JsonSerializable(typeof(IEnumerable))] + +#pragma warning disable CS3016 // Arrays as attribute arguments is not CLS-compliant +[JsonSourceGenerationOptions( + PropertyNameCaseInsensitive = true, + DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull, + PropertyNamingPolicy = JsonKnownNamingPolicy.CamelCase, + Converters = [typeof(DateTimeOffsetConverter)])] +#pragma warning restore CS3016 // Arrays as attribute arguments is not CLS-compliant internal partial class InputJsonSerializerContext : JsonSerializerContext; diff --git a/dotnet/src/webdriver/BiDi/Log/LogModule.cs b/dotnet/src/webdriver/BiDi/Log/LogModule.cs index 34b648d4f7254..286fabd699e54 100644 --- a/dotnet/src/webdriver/BiDi/Log/LogModule.cs +++ b/dotnet/src/webdriver/BiDi/Log/LogModule.cs @@ -17,6 +17,7 @@ // under the License. // +using OpenQA.Selenium.BiDi.Json.Converters; using System; using System.Text.Json.Serialization; using System.Threading.Tasks; @@ -74,4 +75,12 @@ public async Task OnEntryAddedAsync(Action handler, Subs #endregion [JsonSerializable(typeof(LogEntry))] + +#pragma warning disable CS3016 // Arrays as attribute arguments is not CLS-compliant +[JsonSourceGenerationOptions( + PropertyNameCaseInsensitive = true, + DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull, + PropertyNamingPolicy = JsonKnownNamingPolicy.CamelCase, + Converters = [typeof(DateTimeOffsetConverter)])] +#pragma warning restore CS3016 // Arrays as attribute arguments is not CLS-compliant internal partial class LogJsonSerializerContext : JsonSerializerContext; diff --git a/dotnet/src/webdriver/BiDi/Network/Collector.cs b/dotnet/src/webdriver/BiDi/Network/Collector.cs index 6239c25fc3a17..78b945725d163 100644 --- a/dotnet/src/webdriver/BiDi/Network/Collector.cs +++ b/dotnet/src/webdriver/BiDi/Network/Collector.cs @@ -17,12 +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 { internal Collector(string id) diff --git a/dotnet/src/webdriver/BiDi/Network/Intercept.cs b/dotnet/src/webdriver/BiDi/Network/Intercept.cs index 2b5ee6510b52d..c9c251fe6ea7d 100644 --- a/dotnet/src/webdriver/BiDi/Network/Intercept.cs +++ b/dotnet/src/webdriver/BiDi/Network/Intercept.cs @@ -17,6 +17,7 @@ // under the License. // +using OpenQA.Selenium.BiDi.Json.Converters; using System; using System.Collections.Generic; using System.Linq; @@ -25,6 +26,7 @@ namespace OpenQA.Selenium.BiDi.Network; +[JsonConverter(typeof(InterceptConverter))] public sealed class Intercept : IAsyncDisposable { internal Intercept(string id) diff --git a/dotnet/src/webdriver/BiDi/Network/NetworkModule.cs b/dotnet/src/webdriver/BiDi/Network/NetworkModule.cs index d8ad30809e45e..0a9aaa3357529 100644 --- a/dotnet/src/webdriver/BiDi/Network/NetworkModule.cs +++ b/dotnet/src/webdriver/BiDi/Network/NetworkModule.cs @@ -17,6 +17,7 @@ // under the License. // +using OpenQA.Selenium.BiDi.Json.Converters; using System; using System.Collections.Generic; using System.Text.Json.Serialization; @@ -207,4 +208,12 @@ public async Task OnAuthRequiredAsync(Action +using OpenQA.Selenium.BiDi.Json.Converters; using OpenQA.Selenium.BiDi.Permissions; using System.Text.Json.Serialization; using System.Threading.Tasks; @@ -37,4 +38,12 @@ public async Task SetPermissionAsync(PermissionDescriptor d [JsonSerializable(typeof(SetPermissionCommand))] [JsonSerializable(typeof(SetPermissionResult))] + +#pragma warning disable CS3016 // Arrays as attribute arguments is not CLS-compliant +[JsonSourceGenerationOptions( + PropertyNameCaseInsensitive = true, + DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull, + PropertyNamingPolicy = JsonKnownNamingPolicy.CamelCase, + Converters = [typeof(DateTimeOffsetConverter)])] +#pragma warning restore CS3016 // Arrays as attribute arguments is not CLS-compliant internal partial class PermissionsJsonSerializerContext : JsonSerializerContext; diff --git a/dotnet/src/webdriver/BiDi/Script/Handle.cs b/dotnet/src/webdriver/BiDi/Script/Handle.cs index 17a3a70c8be27..12c62a721946d 100644 --- a/dotnet/src/webdriver/BiDi/Script/Handle.cs +++ b/dotnet/src/webdriver/BiDi/Script/Handle.cs @@ -17,10 +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 { public Handle(string id) diff --git a/dotnet/src/webdriver/BiDi/Script/InternalId.cs b/dotnet/src/webdriver/BiDi/Script/InternalId.cs index 31d276236ec20..3d609371bdf4a 100644 --- a/dotnet/src/webdriver/BiDi/Script/InternalId.cs +++ b/dotnet/src/webdriver/BiDi/Script/InternalId.cs @@ -17,10 +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 { public InternalId(string id) diff --git a/dotnet/src/webdriver/BiDi/Script/PreloadScript.cs b/dotnet/src/webdriver/BiDi/Script/PreloadScript.cs index f65053eb8b0c2..ed6ae7efaa5ae 100644 --- a/dotnet/src/webdriver/BiDi/Script/PreloadScript.cs +++ b/dotnet/src/webdriver/BiDi/Script/PreloadScript.cs @@ -17,12 +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 { internal PreloadScript(string id) diff --git a/dotnet/src/webdriver/BiDi/Script/Realm.cs b/dotnet/src/webdriver/BiDi/Script/Realm.cs index 43fcc24df8571..319a93690898e 100644 --- a/dotnet/src/webdriver/BiDi/Script/Realm.cs +++ b/dotnet/src/webdriver/BiDi/Script/Realm.cs @@ -17,10 +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 { public Realm(string id) diff --git a/dotnet/src/webdriver/BiDi/Script/ScriptModule.cs b/dotnet/src/webdriver/BiDi/Script/ScriptModule.cs index 0bd015eeb49a5..5abae98c24dc6 100644 --- a/dotnet/src/webdriver/BiDi/Script/ScriptModule.cs +++ b/dotnet/src/webdriver/BiDi/Script/ScriptModule.cs @@ -17,6 +17,7 @@ // under the License. // +using OpenQA.Selenium.BiDi.Json.Converters; using System; using System.Collections.Generic; using System.Diagnostics.CodeAnalysis; @@ -172,4 +173,12 @@ public async Task OnRealmDestroyedAsync(Action +using OpenQA.Selenium.BiDi.Json.Converters; using System.Collections.Generic; using System.Text.Json.Serialization; using System.Threading.Tasks; @@ -69,4 +70,12 @@ public async Task EndAsync(EndOptions? options = null) [JsonSerializable(typeof(SubscribeResult))] [JsonSerializable(typeof(UnsubscribeByIdCommand))] [JsonSerializable(typeof(UnsubscribeResult))] + +#pragma warning disable CS3016 // Arrays as attribute arguments is not CLS-compliant +[JsonSourceGenerationOptions( + PropertyNameCaseInsensitive = true, + DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull, + PropertyNamingPolicy = JsonKnownNamingPolicy.CamelCase, + Converters = [typeof(DateTimeOffsetConverter)])] +#pragma warning restore CS3016 // Arrays as attribute arguments is not CLS-compliant internal partial class SessionJsonSerializerContext : JsonSerializerContext; diff --git a/dotnet/src/webdriver/BiDi/Storage/StorageModule.cs b/dotnet/src/webdriver/BiDi/Storage/StorageModule.cs index 373873b6be19b..1997c6b19deca 100644 --- a/dotnet/src/webdriver/BiDi/Storage/StorageModule.cs +++ b/dotnet/src/webdriver/BiDi/Storage/StorageModule.cs @@ -17,6 +17,7 @@ // under the License. // +using OpenQA.Selenium.BiDi.Json.Converters; using System.Text.Json.Serialization; using System.Threading.Tasks; @@ -54,4 +55,12 @@ public async Task SetCookieAsync(PartialCookie cookie, SetCooki [JsonSerializable(typeof(SetCookieResult))] [JsonSerializable(typeof(DeleteCookiesCommand))] [JsonSerializable(typeof(DeleteCookiesResult))] + +#pragma warning disable CS3016 // Arrays as attribute arguments is not CLS-compliant +[JsonSourceGenerationOptions( + PropertyNameCaseInsensitive = true, + DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull, + PropertyNamingPolicy = JsonKnownNamingPolicy.CamelCase, + Converters = [typeof(DateTimeOffsetConverter)])] +#pragma warning restore CS3016 // Arrays as attribute arguments is not CLS-compliant internal partial class StorageJsonSerializerContext : JsonSerializerContext; diff --git a/dotnet/src/webdriver/BiDi/WebExtension/Extension.cs b/dotnet/src/webdriver/BiDi/WebExtension/Extension.cs index db19136a2fc2e..0a3b8d7645155 100644 --- a/dotnet/src/webdriver/BiDi/WebExtension/Extension.cs +++ b/dotnet/src/webdriver/BiDi/WebExtension/Extension.cs @@ -17,11 +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 { internal Extension(string id) diff --git a/dotnet/src/webdriver/BiDi/WebExtension/WebExtensionModule.cs b/dotnet/src/webdriver/BiDi/WebExtension/WebExtensionModule.cs index 38f13958530db..e0a972d64b88a 100644 --- a/dotnet/src/webdriver/BiDi/WebExtension/WebExtensionModule.cs +++ b/dotnet/src/webdriver/BiDi/WebExtension/WebExtensionModule.cs @@ -17,6 +17,7 @@ // under the License. // +using OpenQA.Selenium.BiDi.Json.Converters; using System.Text.Json.Serialization; using System.Threading.Tasks; @@ -45,4 +46,12 @@ public async Task UninstallAsync(Extension extension, Uninstall [JsonSerializable(typeof(InstallResult))] [JsonSerializable(typeof(UninstallCommand))] [JsonSerializable(typeof(UninstallResult))] + +#pragma warning disable CS3016 // Arrays as attribute arguments is not CLS-compliant +[JsonSourceGenerationOptions( + PropertyNameCaseInsensitive = true, + DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull, + PropertyNamingPolicy = JsonKnownNamingPolicy.CamelCase, + Converters = [typeof(DateTimeOffsetConverter)])] +#pragma warning restore CS3016 // Arrays as attribute arguments is not CLS-compliant internal partial class WebExtensionJsonSerializerContext : JsonSerializerContext; From 79f723d3b1d907e13642238e1b69a180115256f6 Mon Sep 17 00:00:00 2001 From: Nikolay Borisenko <22616990+nvborisenko@users.noreply.github.com> Date: Wed, 3 Dec 2025 05:33:51 +0300 Subject: [PATCH 03/16] Hidrate the BiDi property example --- dotnet/src/webdriver/BiDi/Browser/BrowserModule.cs | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/dotnet/src/webdriver/BiDi/Browser/BrowserModule.cs b/dotnet/src/webdriver/BiDi/Browser/BrowserModule.cs index c043bbaabd5e2..b3c32aec54612 100644 --- a/dotnet/src/webdriver/BiDi/Browser/BrowserModule.cs +++ b/dotnet/src/webdriver/BiDi/Browser/BrowserModule.cs @@ -36,7 +36,12 @@ public async Task CreateUserContextAsync(CreateUserCont { var @params = new CreateUserContextParameters(options?.AcceptInsecureCerts, options?.Proxy, options?.UnhandledPromptBehavior); - return await Broker.ExecuteCommandAsync(new CreateUserContextCommand(@params), options, _jsonContext.CreateUserContextCommand, _jsonContext.CreateUserContextResult).ConfigureAwait(false); + var result = await Broker.ExecuteCommandAsync(new CreateUserContextCommand(@params), options, _jsonContext.CreateUserContextCommand, _jsonContext.CreateUserContextResult).ConfigureAwait(false); + + // Hidrate the BiDi property + result.UserContext.BiDi = BiDi; + + return result; } public async Task GetUserContextsAsync(GetUserContextsOptions? options = null) From cafbba5f76cf259a40431c768706fc04ed5a7883 Mon Sep 17 00:00:00 2001 From: Nikolay Borisenko <22616990+nvborisenko@users.noreply.github.com> Date: Wed, 3 Dec 2025 05:46:43 +0300 Subject: [PATCH 04/16] One more hidrate example --- .../BiDi/BrowsingContext/BrowsingContextModule.cs | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/dotnet/src/webdriver/BiDi/BrowsingContext/BrowsingContextModule.cs b/dotnet/src/webdriver/BiDi/BrowsingContext/BrowsingContextModule.cs index b922e1cfa6faa..b71e3d8654f97 100644 --- a/dotnet/src/webdriver/BiDi/BrowsingContext/BrowsingContextModule.cs +++ b/dotnet/src/webdriver/BiDi/BrowsingContext/BrowsingContextModule.cs @@ -95,7 +95,15 @@ public async Task GetTreeAsync(GetTreeOptions? options = null) { var @params = new GetTreeParameters(options?.MaxDepth, options?.Root); - return await Broker.ExecuteCommandAsync(new GetTreeCommand(@params), options, _jsonContext.GetTreeCommand, _jsonContext.GetTreeResult).ConfigureAwait(false); + var result = await Broker.ExecuteCommandAsync(new GetTreeCommand(@params), options, _jsonContext.GetTreeCommand, _jsonContext.GetTreeResult).ConfigureAwait(false); + + // Hidrate the BrowsingContext property of each BrowsingContextInfo + foreach (var contextInfo in result.Contexts) + { + contextInfo.Context.BiDi = BiDi; + } + + return result; } public async Task PrintAsync(BrowsingContext context, PrintOptions? options = null) From d7956b45172596b0ca3ebd8a335dd0ce37e89597 Mon Sep 17 00:00:00 2001 From: Nikolay Borisenko <22616990+nvborisenko@users.noreply.github.com> Date: Wed, 3 Dec 2025 06:04:23 +0300 Subject: [PATCH 05/16] Unified hidration for top level types --- dotnet/src/webdriver/BiDi/Broker.cs | 5 +++++ dotnet/src/webdriver/BiDi/Browser/BrowserModule.cs | 7 +------ .../BiDi/Browser/CreateUserContextCommand.cs | 8 +++++++- .../BiDi/BrowsingContext/BrowsingContextModule.cs | 10 +--------- .../webdriver/BiDi/BrowsingContext/GetTreeCommand.cs | 11 ++++++++++- dotnet/src/webdriver/BiDi/EventArgs.cs | 7 ++++++- dotnet/src/webdriver/BiDi/IBiDiHidrable.cs | 6 ++++++ 7 files changed, 36 insertions(+), 18 deletions(-) create mode 100644 dotnet/src/webdriver/BiDi/IBiDiHidrable.cs diff --git a/dotnet/src/webdriver/BiDi/Broker.cs b/dotnet/src/webdriver/BiDi/Broker.cs index 6e74edcfb5522..65d08d1130e78 100644 --- a/dotnet/src/webdriver/BiDi/Broker.cs +++ b/dotnet/src/webdriver/BiDi/Broker.cs @@ -279,6 +279,11 @@ private void ProcessReceivedMessage(byte[]? data) var commandResult = JsonSerializer.Deserialize(ref resultReader, command.JsonResultTypeInfo) ?? throw new JsonException("Remote end returned null command result in the 'result' property."); + if (commandResult is IBiDiHidrable bidiHidrable) + { + bidiHidrable.Hidrate(_bidi); + } + command.TaskCompletionSource.SetResult((EmptyResult)commandResult); } catch (Exception ex) diff --git a/dotnet/src/webdriver/BiDi/Browser/BrowserModule.cs b/dotnet/src/webdriver/BiDi/Browser/BrowserModule.cs index b3c32aec54612..c043bbaabd5e2 100644 --- a/dotnet/src/webdriver/BiDi/Browser/BrowserModule.cs +++ b/dotnet/src/webdriver/BiDi/Browser/BrowserModule.cs @@ -36,12 +36,7 @@ public async Task CreateUserContextAsync(CreateUserCont { var @params = new CreateUserContextParameters(options?.AcceptInsecureCerts, options?.Proxy, options?.UnhandledPromptBehavior); - var result = await Broker.ExecuteCommandAsync(new CreateUserContextCommand(@params), options, _jsonContext.CreateUserContextCommand, _jsonContext.CreateUserContextResult).ConfigureAwait(false); - - // Hidrate the BiDi property - result.UserContext.BiDi = BiDi; - - return result; + return await Broker.ExecuteCommandAsync(new CreateUserContextCommand(@params), options, _jsonContext.CreateUserContextCommand, _jsonContext.CreateUserContextResult).ConfigureAwait(false); } public async Task GetUserContextsAsync(GetUserContextsOptions? options = null) diff --git a/dotnet/src/webdriver/BiDi/Browser/CreateUserContextCommand.cs b/dotnet/src/webdriver/BiDi/Browser/CreateUserContextCommand.cs index b3331f6125b25..a5c4b31174084 100644 --- a/dotnet/src/webdriver/BiDi/Browser/CreateUserContextCommand.cs +++ b/dotnet/src/webdriver/BiDi/Browser/CreateUserContextCommand.cs @@ -33,4 +33,10 @@ public sealed class CreateUserContextOptions : CommandOptions public Session.UserPromptHandler? UnhandledPromptBehavior { get; set; } } -public sealed record CreateUserContextResult(UserContext UserContext) : UserContextInfo(UserContext); +public sealed record CreateUserContextResult(UserContext UserContext) : UserContextInfo(UserContext), IBiDiHidrable +{ + void IBiDiHidrable.Hidrate(BiDi bidi) + { + UserContext.BiDi = bidi; + } +} diff --git a/dotnet/src/webdriver/BiDi/BrowsingContext/BrowsingContextModule.cs b/dotnet/src/webdriver/BiDi/BrowsingContext/BrowsingContextModule.cs index b71e3d8654f97..b922e1cfa6faa 100644 --- a/dotnet/src/webdriver/BiDi/BrowsingContext/BrowsingContextModule.cs +++ b/dotnet/src/webdriver/BiDi/BrowsingContext/BrowsingContextModule.cs @@ -95,15 +95,7 @@ public async Task GetTreeAsync(GetTreeOptions? options = null) { var @params = new GetTreeParameters(options?.MaxDepth, options?.Root); - var result = await Broker.ExecuteCommandAsync(new GetTreeCommand(@params), options, _jsonContext.GetTreeCommand, _jsonContext.GetTreeResult).ConfigureAwait(false); - - // Hidrate the BrowsingContext property of each BrowsingContextInfo - foreach (var contextInfo in result.Contexts) - { - contextInfo.Context.BiDi = BiDi; - } - - return result; + return await Broker.ExecuteCommandAsync(new GetTreeCommand(@params), options, _jsonContext.GetTreeCommand, _jsonContext.GetTreeResult).ConfigureAwait(false); } public async Task PrintAsync(BrowsingContext context, PrintOptions? options = null) diff --git a/dotnet/src/webdriver/BiDi/BrowsingContext/GetTreeCommand.cs b/dotnet/src/webdriver/BiDi/BrowsingContext/GetTreeCommand.cs index 425cea68e0d5e..cc637dd6d6e2a 100644 --- a/dotnet/src/webdriver/BiDi/BrowsingContext/GetTreeCommand.cs +++ b/dotnet/src/webdriver/BiDi/BrowsingContext/GetTreeCommand.cs @@ -45,4 +45,13 @@ public sealed record BrowsingContextGetTreeOptions public long? MaxDepth { get; set; } } -public sealed record GetTreeResult(IReadOnlyList Contexts) : EmptyResult; +public sealed record GetTreeResult(IReadOnlyList Contexts) : EmptyResult, IBiDiHidrable +{ + void IBiDiHidrable.Hidrate(BiDi bidi) + { + foreach (var contextInfo in Contexts) + { + contextInfo.Context.BiDi = bidi; + } + } +} diff --git a/dotnet/src/webdriver/BiDi/EventArgs.cs b/dotnet/src/webdriver/BiDi/EventArgs.cs index 2e1b59ec59e01..347307280b43a 100644 --- a/dotnet/src/webdriver/BiDi/EventArgs.cs +++ b/dotnet/src/webdriver/BiDi/EventArgs.cs @@ -21,10 +21,15 @@ namespace OpenQA.Selenium.BiDi; -public abstract record EventArgs +public abstract record EventArgs : IBiDiHidrable { [JsonIgnore] public BiDi BiDi { get; internal set; } + + void IBiDiHidrable.Hidrate(BiDi bidi) + { + BiDi = bidi; + } } public abstract record BrowsingContextEventArgs(BrowsingContext.BrowsingContext Context) diff --git a/dotnet/src/webdriver/BiDi/IBiDiHidrable.cs b/dotnet/src/webdriver/BiDi/IBiDiHidrable.cs new file mode 100644 index 0000000000000..fd64586330c4b --- /dev/null +++ b/dotnet/src/webdriver/BiDi/IBiDiHidrable.cs @@ -0,0 +1,6 @@ +namespace OpenQA.Selenium.BiDi; + +internal interface IBiDiHidrable +{ + internal void Hidrate(BiDi bidi); +} From aaddb1e76938fe0720e731f1b126d208f0ed9172 Mon Sep 17 00:00:00 2001 From: Nikolay Borisenko <22616990+nvborisenko@users.noreply.github.com> Date: Wed, 3 Dec 2025 06:21:34 +0300 Subject: [PATCH 06/16] Fix name --- dotnet/src/webdriver/BiDi/Broker.cs | 4 +-- .../BiDi/Browser/CreateUserContextCommand.cs | 4 +-- .../BiDi/BrowsingContext/GetTreeCommand.cs | 4 +-- dotnet/src/webdriver/BiDi/EventArgs.cs | 4 +-- dotnet/src/webdriver/BiDi/IBiDiHidrable.cs | 6 ----- dotnet/src/webdriver/BiDi/IBiDiHydratable.cs | 25 +++++++++++++++++++ 6 files changed, 33 insertions(+), 14 deletions(-) delete mode 100644 dotnet/src/webdriver/BiDi/IBiDiHidrable.cs create mode 100644 dotnet/src/webdriver/BiDi/IBiDiHydratable.cs diff --git a/dotnet/src/webdriver/BiDi/Broker.cs b/dotnet/src/webdriver/BiDi/Broker.cs index 65d08d1130e78..4b03887bf323b 100644 --- a/dotnet/src/webdriver/BiDi/Broker.cs +++ b/dotnet/src/webdriver/BiDi/Broker.cs @@ -279,9 +279,9 @@ private void ProcessReceivedMessage(byte[]? data) var commandResult = JsonSerializer.Deserialize(ref resultReader, command.JsonResultTypeInfo) ?? throw new JsonException("Remote end returned null command result in the 'result' property."); - if (commandResult is IBiDiHidrable bidiHidrable) + if (commandResult is IBiDiHydratable bidiHydratable) { - bidiHidrable.Hidrate(_bidi); + bidiHydratable.Hydrate(_bidi); } command.TaskCompletionSource.SetResult((EmptyResult)commandResult); diff --git a/dotnet/src/webdriver/BiDi/Browser/CreateUserContextCommand.cs b/dotnet/src/webdriver/BiDi/Browser/CreateUserContextCommand.cs index a5c4b31174084..59c94cca21ae2 100644 --- a/dotnet/src/webdriver/BiDi/Browser/CreateUserContextCommand.cs +++ b/dotnet/src/webdriver/BiDi/Browser/CreateUserContextCommand.cs @@ -33,9 +33,9 @@ public sealed class CreateUserContextOptions : CommandOptions public Session.UserPromptHandler? UnhandledPromptBehavior { get; set; } } -public sealed record CreateUserContextResult(UserContext UserContext) : UserContextInfo(UserContext), IBiDiHidrable +public sealed record CreateUserContextResult(UserContext UserContext) : UserContextInfo(UserContext), IBiDiHydratable { - void IBiDiHidrable.Hidrate(BiDi bidi) + void IBiDiHydratable.Hydrate(BiDi bidi) { UserContext.BiDi = bidi; } diff --git a/dotnet/src/webdriver/BiDi/BrowsingContext/GetTreeCommand.cs b/dotnet/src/webdriver/BiDi/BrowsingContext/GetTreeCommand.cs index cc637dd6d6e2a..8798dd7d7ef8a 100644 --- a/dotnet/src/webdriver/BiDi/BrowsingContext/GetTreeCommand.cs +++ b/dotnet/src/webdriver/BiDi/BrowsingContext/GetTreeCommand.cs @@ -45,9 +45,9 @@ public sealed record BrowsingContextGetTreeOptions public long? MaxDepth { get; set; } } -public sealed record GetTreeResult(IReadOnlyList Contexts) : EmptyResult, IBiDiHidrable +public sealed record GetTreeResult(IReadOnlyList Contexts) : EmptyResult, IBiDiHydratable { - void IBiDiHidrable.Hidrate(BiDi bidi) + void IBiDiHydratable.Hydrate(BiDi bidi) { foreach (var contextInfo in Contexts) { diff --git a/dotnet/src/webdriver/BiDi/EventArgs.cs b/dotnet/src/webdriver/BiDi/EventArgs.cs index 347307280b43a..2d683993d2e26 100644 --- a/dotnet/src/webdriver/BiDi/EventArgs.cs +++ b/dotnet/src/webdriver/BiDi/EventArgs.cs @@ -21,12 +21,12 @@ namespace OpenQA.Selenium.BiDi; -public abstract record EventArgs : IBiDiHidrable +public abstract record EventArgs : IBiDiHydratable { [JsonIgnore] public BiDi BiDi { get; internal set; } - void IBiDiHidrable.Hidrate(BiDi bidi) + void IBiDiHydratable.Hydrate(BiDi bidi) { BiDi = bidi; } diff --git a/dotnet/src/webdriver/BiDi/IBiDiHidrable.cs b/dotnet/src/webdriver/BiDi/IBiDiHidrable.cs deleted file mode 100644 index fd64586330c4b..0000000000000 --- a/dotnet/src/webdriver/BiDi/IBiDiHidrable.cs +++ /dev/null @@ -1,6 +0,0 @@ -namespace OpenQA.Selenium.BiDi; - -internal interface IBiDiHidrable -{ - internal void Hidrate(BiDi bidi); -} diff --git a/dotnet/src/webdriver/BiDi/IBiDiHydratable.cs b/dotnet/src/webdriver/BiDi/IBiDiHydratable.cs new file mode 100644 index 0000000000000..2e9775a380777 --- /dev/null +++ b/dotnet/src/webdriver/BiDi/IBiDiHydratable.cs @@ -0,0 +1,25 @@ +// +// Licensed to the Software Freedom Conservancy (SFC) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The SFC licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. +// + +namespace OpenQA.Selenium.BiDi; + +public interface IBiDiHydratable +{ + internal void Hydrate(BiDi bidi); +} From 25389bdf866bfd0718b7c0f945a113a222c15903 Mon Sep 17 00:00:00 2001 From: Nikolay Borisenko <22616990+nvborisenko@users.noreply.github.com> Date: Wed, 3 Dec 2025 06:57:14 +0300 Subject: [PATCH 07/16] Hydrate event args --- dotnet/src/webdriver/BiDi/Broker.cs | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/dotnet/src/webdriver/BiDi/Broker.cs b/dotnet/src/webdriver/BiDi/Broker.cs index 4b03887bf323b..fb7d960c6b350 100644 --- a/dotnet/src/webdriver/BiDi/Broker.cs +++ b/dotnet/src/webdriver/BiDi/Broker.cs @@ -309,6 +309,11 @@ private void ProcessReceivedMessage(byte[]? data) { var eventArgs = (EventArgs)JsonSerializer.Deserialize(ref paramsReader, eventInfo)!; + if (eventArgs is IBiDiHydratable bidiHydratable) + { + bidiHydratable.Hydrate(_bidi); + } + var messageEvent = (method, eventArgs); _pendingEvents.Add(messageEvent); } From 61ad32033f8165cb965fadcf92fba03a19e6fb2e Mon Sep 17 00:00:00 2001 From: Nikolay Borisenko <22616990+nvborisenko@users.noreply.github.com> Date: Wed, 3 Dec 2025 06:57:53 +0300 Subject: [PATCH 08/16] Hydrate AddInterceptResult --- dotnet/src/webdriver/BiDi/Network/AddInterceptCommand.cs | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/dotnet/src/webdriver/BiDi/Network/AddInterceptCommand.cs b/dotnet/src/webdriver/BiDi/Network/AddInterceptCommand.cs index 23055edfa82fe..043a299bc3e51 100644 --- a/dotnet/src/webdriver/BiDi/Network/AddInterceptCommand.cs +++ b/dotnet/src/webdriver/BiDi/Network/AddInterceptCommand.cs @@ -47,7 +47,13 @@ public record BrowsingContextAddInterceptOptions public IEnumerable? UrlPatterns { get; set; } } -public sealed record AddInterceptResult(Intercept Intercept) : EmptyResult; +public sealed record AddInterceptResult(Intercept Intercept) : EmptyResult, IBiDiHydratable +{ + void IBiDiHydratable.Hydrate(BiDi bidi) + { + Intercept.BiDi = bidi; + } +} [JsonConverter(typeof(CamelCaseEnumConverter))] public enum InterceptPhase From 2d20a435e40ee81927ef2c86f5afb772d04692b7 Mon Sep 17 00:00:00 2001 From: Nikolay Borisenko <22616990+nvborisenko@users.noreply.github.com> Date: Wed, 3 Dec 2025 06:59:38 +0300 Subject: [PATCH 09/16] Hydrate AddDataCollectorResult --- .../src/webdriver/BiDi/Network/AddDataCollectorCommand.cs | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/dotnet/src/webdriver/BiDi/Network/AddDataCollectorCommand.cs b/dotnet/src/webdriver/BiDi/Network/AddDataCollectorCommand.cs index ea831d1cec4c6..a6b14aa6ed8ee 100644 --- a/dotnet/src/webdriver/BiDi/Network/AddDataCollectorCommand.cs +++ b/dotnet/src/webdriver/BiDi/Network/AddDataCollectorCommand.cs @@ -37,7 +37,13 @@ public class AddDataCollectorOptions : CommandOptions public IEnumerable? UserContexts { get; set; } } -public sealed record AddDataCollectorResult(Collector Collector) : EmptyResult; +public sealed record AddDataCollectorResult(Collector Collector) : EmptyResult, IBiDiHydratable +{ + void IBiDiHydratable.Hydrate(BiDi bidi) + { + Collector.BiDi = bidi; + } +} [JsonConverter(typeof(CamelCaseEnumConverter))] public enum DataType From 3f482c0f9ff8eb0c4498ac931840432b6b1368ae Mon Sep 17 00:00:00 2001 From: Nikolay Borisenko <22616990+nvborisenko@users.noreply.github.com> Date: Wed, 3 Dec 2025 07:01:55 +0300 Subject: [PATCH 10/16] Hydrate CreateResult --- .../src/webdriver/BiDi/BrowsingContext/CreateCommand.cs | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/dotnet/src/webdriver/BiDi/BrowsingContext/CreateCommand.cs b/dotnet/src/webdriver/BiDi/BrowsingContext/CreateCommand.cs index 892e3cc3a3674..44bfd0385a830 100644 --- a/dotnet/src/webdriver/BiDi/BrowsingContext/CreateCommand.cs +++ b/dotnet/src/webdriver/BiDi/BrowsingContext/CreateCommand.cs @@ -43,4 +43,10 @@ public enum ContextType Window } -public sealed record CreateResult(BrowsingContext Context) : EmptyResult; +public sealed record CreateResult(BrowsingContext Context) : EmptyResult, IBiDiHydratable +{ + void IBiDiHydratable.Hydrate(BiDi bidi) + { + Context.BiDi = bidi; + } +} From 00d499e3abaa5c41f58eb6f8dd510def623607d0 Mon Sep 17 00:00:00 2001 From: Nikolay Borisenko <22616990+nvborisenko@users.noreply.github.com> Date: Wed, 3 Dec 2025 07:06:39 +0300 Subject: [PATCH 11/16] Hydrate AddPreloadScriptResult --- .../src/webdriver/BiDi/Script/AddPreloadScriptCommand.cs | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/dotnet/src/webdriver/BiDi/Script/AddPreloadScriptCommand.cs b/dotnet/src/webdriver/BiDi/Script/AddPreloadScriptCommand.cs index 4cb6e75b0e7f5..3cbb761cab957 100644 --- a/dotnet/src/webdriver/BiDi/Script/AddPreloadScriptCommand.cs +++ b/dotnet/src/webdriver/BiDi/Script/AddPreloadScriptCommand.cs @@ -17,7 +17,6 @@ // under the License. // -using OpenQA.Selenium.Internal; using System.Collections.Generic; using System.Diagnostics.CodeAnalysis; @@ -52,4 +51,10 @@ public sealed record BrowsingContextAddPreloadScriptOptions public string? Sandbox { get; set; } } -public sealed record AddPreloadScriptResult(PreloadScript Script) : EmptyResult; +public sealed record AddPreloadScriptResult(PreloadScript Script) : EmptyResult, IBiDiHydratable +{ + void IBiDiHydratable.Hydrate(BiDi bidi) + { + Script.BiDi = bidi; + } +} From 7204604880bd6b8e8c335509535e0a574230fcdd Mon Sep 17 00:00:00 2001 From: Nikolay Borisenko <22616990+nvborisenko@users.noreply.github.com> Date: Wed, 3 Dec 2025 13:51:44 +0300 Subject: [PATCH 12/16] Hydrate InstallResult --- dotnet/src/webdriver/BiDi/WebExtension/InstallCommand.cs | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/dotnet/src/webdriver/BiDi/WebExtension/InstallCommand.cs b/dotnet/src/webdriver/BiDi/WebExtension/InstallCommand.cs index d7c4e29d3d756..4fa8a134ca346 100644 --- a/dotnet/src/webdriver/BiDi/WebExtension/InstallCommand.cs +++ b/dotnet/src/webdriver/BiDi/WebExtension/InstallCommand.cs @@ -41,4 +41,10 @@ public sealed record ExtensionPath(string Path) : ExtensionData; public sealed class InstallOptions : CommandOptions; -public sealed record InstallResult(Extension Extension) : EmptyResult; +public sealed record InstallResult(Extension Extension) : EmptyResult, IBiDiHydratable +{ + void IBiDiHydratable.Hydrate(BiDi bidi) + { + Extension.BiDi = bidi; + } +} From a465945d495a2e020cc8d6cd69efdb1982228a9f Mon Sep 17 00:00:00 2001 From: Nikolay Borisenko <22616990+nvborisenko@users.noreply.github.com> Date: Wed, 3 Dec 2025 14:56:04 +0300 Subject: [PATCH 13/16] Throw if not hydrated --- dotnet/src/webdriver/BiDi/Browser/UserContext.cs | 8 +++++++- .../webdriver/BiDi/BrowsingContext/BrowsingContext.cs | 8 +++++++- dotnet/src/webdriver/BiDi/EventArgs.cs | 9 ++++++++- dotnet/src/webdriver/BiDi/Network/Collector.cs | 8 +++++++- dotnet/src/webdriver/BiDi/Network/Intercept.cs | 8 +++++++- dotnet/src/webdriver/BiDi/Script/Handle.cs | 9 ++++++++- dotnet/src/webdriver/BiDi/Script/InternalId.cs | 9 ++++++++- dotnet/src/webdriver/BiDi/Script/PreloadScript.cs | 8 +++++++- dotnet/src/webdriver/BiDi/Script/Realm.cs | 9 ++++++++- dotnet/src/webdriver/BiDi/WebExtension/Extension.cs | 9 ++++++++- 10 files changed, 75 insertions(+), 10 deletions(-) diff --git a/dotnet/src/webdriver/BiDi/Browser/UserContext.cs b/dotnet/src/webdriver/BiDi/Browser/UserContext.cs index 11624c981e4e8..b3f11478d2db7 100644 --- a/dotnet/src/webdriver/BiDi/Browser/UserContext.cs +++ b/dotnet/src/webdriver/BiDi/Browser/UserContext.cs @@ -27,6 +27,8 @@ namespace OpenQA.Selenium.BiDi.Browser; [JsonConverter(typeof(BrowserUserContextConverter))] public sealed class UserContext : IEquatable, IAsyncDisposable { + private BiDi? _bidi; + internal UserContext(string id) { Id = id; @@ -35,7 +37,11 @@ internal UserContext(string id) internal string Id { get; } [JsonIgnore] - public BiDi BiDi { get; internal set; } + public BiDi BiDi + { + get => _bidi ?? throw new InvalidOperationException($"{nameof(BiDi)} instance has not been hydrated."); + internal set => _bidi = value; + } public Task RemoveAsync() { diff --git a/dotnet/src/webdriver/BiDi/BrowsingContext/BrowsingContext.cs b/dotnet/src/webdriver/BiDi/BrowsingContext/BrowsingContext.cs index 6b1a14ebdeb2f..66bf3de09f5e1 100644 --- a/dotnet/src/webdriver/BiDi/BrowsingContext/BrowsingContext.cs +++ b/dotnet/src/webdriver/BiDi/BrowsingContext/BrowsingContext.cs @@ -41,8 +41,14 @@ internal BrowsingContext(string id) internal string Id { get; } + private BiDi? _bidi; + [JsonIgnore] - public BiDi BiDi { get; internal set; } + public BiDi BiDi + { + get => _bidi ?? throw new InvalidOperationException("BiDi instance has not been hydrated."); + internal set => _bidi = value; + } [JsonIgnore] public BrowsingContextLogModule Log => _logModule ?? Interlocked.CompareExchange(ref _logModule, new BrowsingContextLogModule(this, BiDi.Log), null) ?? _logModule; diff --git a/dotnet/src/webdriver/BiDi/EventArgs.cs b/dotnet/src/webdriver/BiDi/EventArgs.cs index 2d683993d2e26..2d81c4914367c 100644 --- a/dotnet/src/webdriver/BiDi/EventArgs.cs +++ b/dotnet/src/webdriver/BiDi/EventArgs.cs @@ -17,14 +17,21 @@ // under the License. // +using System; using System.Text.Json.Serialization; namespace OpenQA.Selenium.BiDi; public abstract record EventArgs : IBiDiHydratable { + private BiDi? _bidi; + [JsonIgnore] - public BiDi BiDi { get; internal set; } + public BiDi BiDi + { + get => _bidi ?? throw new InvalidOperationException($"{nameof(BiDi)} instance has not been hydrated."); + internal set => _bidi = value; + } void IBiDiHydratable.Hydrate(BiDi bidi) { diff --git a/dotnet/src/webdriver/BiDi/Network/Collector.cs b/dotnet/src/webdriver/BiDi/Network/Collector.cs index 78b945725d163..a61e5623ba48b 100644 --- a/dotnet/src/webdriver/BiDi/Network/Collector.cs +++ b/dotnet/src/webdriver/BiDi/Network/Collector.cs @@ -27,6 +27,8 @@ namespace OpenQA.Selenium.BiDi.Network; [JsonConverter(typeof(CollectorConverter))] public sealed class Collector : IAsyncDisposable { + private BiDi? _bidi; + internal Collector(string id) { Id = id; @@ -35,7 +37,11 @@ internal Collector(string id) internal string Id { get; } [JsonIgnore] - public BiDi BiDi { get; internal set; } + public BiDi BiDi + { + get => _bidi ?? throw new InvalidOperationException($"{nameof(BiDi)} instance has not been hydrated."); + internal set => _bidi = value; + } public async Task RemoveAsync() { diff --git a/dotnet/src/webdriver/BiDi/Network/Intercept.cs b/dotnet/src/webdriver/BiDi/Network/Intercept.cs index c9c251fe6ea7d..3bf49a99d1e84 100644 --- a/dotnet/src/webdriver/BiDi/Network/Intercept.cs +++ b/dotnet/src/webdriver/BiDi/Network/Intercept.cs @@ -29,6 +29,8 @@ namespace OpenQA.Selenium.BiDi.Network; [JsonConverter(typeof(InterceptConverter))] public sealed class Intercept : IAsyncDisposable { + private BiDi? _bidi; + internal Intercept(string id) { Id = id; @@ -37,7 +39,11 @@ internal Intercept(string id) internal string Id { get; } [JsonIgnore] - public BiDi BiDi { get; internal set; } + public BiDi BiDi + { + get => _bidi ?? throw new InvalidOperationException($"{nameof(BiDi)} instance has not been hydrated."); + internal set => _bidi = value; + } IList OnBeforeRequestSentSubscriptions { get; } = []; IList OnResponseStartedSubscriptions { get; } = []; diff --git a/dotnet/src/webdriver/BiDi/Script/Handle.cs b/dotnet/src/webdriver/BiDi/Script/Handle.cs index 12c62a721946d..23d6e639c6220 100644 --- a/dotnet/src/webdriver/BiDi/Script/Handle.cs +++ b/dotnet/src/webdriver/BiDi/Script/Handle.cs @@ -18,6 +18,7 @@ // using OpenQA.Selenium.BiDi.Json.Converters; +using System; using System.Text.Json.Serialization; namespace OpenQA.Selenium.BiDi.Script; @@ -25,6 +26,8 @@ namespace OpenQA.Selenium.BiDi.Script; [JsonConverter(typeof(HandleConverter))] public sealed class Handle { + private BiDi? _bidi; + public Handle(string id) { Id = id; @@ -33,5 +36,9 @@ public Handle(string id) public string Id { get; } [JsonIgnore] - public BiDi BiDi { get; internal set; } + public BiDi BiDi + { + get => _bidi ?? throw new InvalidOperationException($"{nameof(BiDi)} instance has not been hydrated."); + internal set => _bidi = value; + } } diff --git a/dotnet/src/webdriver/BiDi/Script/InternalId.cs b/dotnet/src/webdriver/BiDi/Script/InternalId.cs index 3d609371bdf4a..45fb379d88d9c 100644 --- a/dotnet/src/webdriver/BiDi/Script/InternalId.cs +++ b/dotnet/src/webdriver/BiDi/Script/InternalId.cs @@ -18,6 +18,7 @@ // using OpenQA.Selenium.BiDi.Json.Converters; +using System; using System.Text.Json.Serialization; namespace OpenQA.Selenium.BiDi.Script; @@ -32,6 +33,12 @@ public InternalId(string id) public string Id { get; } + private BiDi? _bidi; + [JsonIgnore] - public BiDi BiDi { get; internal set; } + public BiDi BiDi + { + get => _bidi ?? throw new InvalidOperationException("BiDi instance has not been hydrated."); + internal set => _bidi = value; + } } diff --git a/dotnet/src/webdriver/BiDi/Script/PreloadScript.cs b/dotnet/src/webdriver/BiDi/Script/PreloadScript.cs index ed6ae7efaa5ae..15af12f727bdc 100644 --- a/dotnet/src/webdriver/BiDi/Script/PreloadScript.cs +++ b/dotnet/src/webdriver/BiDi/Script/PreloadScript.cs @@ -27,6 +27,8 @@ namespace OpenQA.Selenium.BiDi.Script; [JsonConverter(typeof(PreloadScriptConverter))] public sealed class PreloadScript : IAsyncDisposable { + private BiDi? _bidi; + internal PreloadScript(string id) { Id = id; @@ -35,7 +37,11 @@ internal PreloadScript(string id) public string Id { get; } [JsonIgnore] - public BiDi BiDi { get; internal set; } + public BiDi BiDi + { + get => _bidi ?? throw new InvalidOperationException($"{nameof(BiDi)} instance has not been hydrated."); + internal set => _bidi = value; + } public Task RemoveAsync() { diff --git a/dotnet/src/webdriver/BiDi/Script/Realm.cs b/dotnet/src/webdriver/BiDi/Script/Realm.cs index 319a93690898e..92a49a58e2807 100644 --- a/dotnet/src/webdriver/BiDi/Script/Realm.cs +++ b/dotnet/src/webdriver/BiDi/Script/Realm.cs @@ -18,6 +18,7 @@ // using OpenQA.Selenium.BiDi.Json.Converters; +using System; using System.Text.Json.Serialization; namespace OpenQA.Selenium.BiDi.Script; @@ -32,6 +33,12 @@ public Realm(string id) public string Id { get; } + private BiDi? _bidi; + [JsonIgnore] - public BiDi BiDi { get; internal set; } + public BiDi BiDi + { + get => _bidi ?? throw new InvalidOperationException("BiDi instance has not been hydrated."); + internal set => _bidi = value; + } } diff --git a/dotnet/src/webdriver/BiDi/WebExtension/Extension.cs b/dotnet/src/webdriver/BiDi/WebExtension/Extension.cs index 0a3b8d7645155..7525800e5303d 100644 --- a/dotnet/src/webdriver/BiDi/WebExtension/Extension.cs +++ b/dotnet/src/webdriver/BiDi/WebExtension/Extension.cs @@ -18,6 +18,7 @@ // using OpenQA.Selenium.BiDi.Json.Converters; +using System; using System.Text.Json.Serialization; using System.Threading.Tasks; @@ -26,6 +27,8 @@ namespace OpenQA.Selenium.BiDi.WebExtension; [JsonConverter(typeof(WebExtensionConverter))] public sealed class Extension { + private BiDi? _bidi; + internal Extension(string id) { Id = id; @@ -34,7 +37,11 @@ internal Extension(string id) internal string Id { get; } [JsonIgnore] - public BiDi BiDi { get; internal set; } + public BiDi BiDi + { + get => _bidi ?? throw new InvalidOperationException("BiDi instance has not been hydrated."); + internal set => _bidi = value; + } public Task UninstallAsync(UninstallOptions? options = null) { From 4e487dfb58acc5f8b2f045759ee15ec03b880f1d Mon Sep 17 00:00:00 2001 From: Nikolay Borisenko <22616990+nvborisenko@users.noreply.github.com> Date: Wed, 3 Dec 2025 15:03:42 +0300 Subject: [PATCH 14/16] Fix property name for exception --- dotnet/src/webdriver/BiDi/BrowsingContext/BrowsingContext.cs | 2 +- dotnet/src/webdriver/BiDi/Script/InternalId.cs | 2 +- dotnet/src/webdriver/BiDi/Script/Realm.cs | 2 +- dotnet/src/webdriver/BiDi/WebExtension/Extension.cs | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/dotnet/src/webdriver/BiDi/BrowsingContext/BrowsingContext.cs b/dotnet/src/webdriver/BiDi/BrowsingContext/BrowsingContext.cs index 66bf3de09f5e1..59e5c50597c2a 100644 --- a/dotnet/src/webdriver/BiDi/BrowsingContext/BrowsingContext.cs +++ b/dotnet/src/webdriver/BiDi/BrowsingContext/BrowsingContext.cs @@ -46,7 +46,7 @@ internal BrowsingContext(string id) [JsonIgnore] public BiDi BiDi { - get => _bidi ?? throw new InvalidOperationException("BiDi instance has not been hydrated."); + get => _bidi ?? throw new InvalidOperationException($"{nameof(BiDi)} instance has not been hydrated."); internal set => _bidi = value; } diff --git a/dotnet/src/webdriver/BiDi/Script/InternalId.cs b/dotnet/src/webdriver/BiDi/Script/InternalId.cs index 45fb379d88d9c..1b8c9f1820123 100644 --- a/dotnet/src/webdriver/BiDi/Script/InternalId.cs +++ b/dotnet/src/webdriver/BiDi/Script/InternalId.cs @@ -38,7 +38,7 @@ public InternalId(string id) [JsonIgnore] public BiDi BiDi { - get => _bidi ?? throw new InvalidOperationException("BiDi instance has not been hydrated."); + get => _bidi ?? throw new InvalidOperationException($"{nameof(BiDi)} instance has not been hydrated."); internal set => _bidi = value; } } diff --git a/dotnet/src/webdriver/BiDi/Script/Realm.cs b/dotnet/src/webdriver/BiDi/Script/Realm.cs index 92a49a58e2807..17e1f8b296e22 100644 --- a/dotnet/src/webdriver/BiDi/Script/Realm.cs +++ b/dotnet/src/webdriver/BiDi/Script/Realm.cs @@ -38,7 +38,7 @@ public Realm(string id) [JsonIgnore] public BiDi BiDi { - get => _bidi ?? throw new InvalidOperationException("BiDi instance has not been hydrated."); + get => _bidi ?? throw new InvalidOperationException($"{nameof(BiDi)} instance has not been hydrated."); internal set => _bidi = value; } } diff --git a/dotnet/src/webdriver/BiDi/WebExtension/Extension.cs b/dotnet/src/webdriver/BiDi/WebExtension/Extension.cs index 7525800e5303d..f44b1419d9797 100644 --- a/dotnet/src/webdriver/BiDi/WebExtension/Extension.cs +++ b/dotnet/src/webdriver/BiDi/WebExtension/Extension.cs @@ -39,7 +39,7 @@ internal Extension(string id) [JsonIgnore] public BiDi BiDi { - get => _bidi ?? throw new InvalidOperationException("BiDi instance has not been hydrated."); + get => _bidi ?? throw new InvalidOperationException($"{nameof(BiDi)} instance has not been hydrated."); internal set => _bidi = value; } From 1501af1655ed67e9f6759b7a5b8a8098c0e771ba Mon Sep 17 00:00:00 2001 From: Nikolay Borisenko <22616990+nvborisenko@users.noreply.github.com> Date: Wed, 3 Dec 2025 21:39:02 +0300 Subject: [PATCH 15/16] Don't hydrate primitives except BrowsingContext --- .../BiDi/Browser/CreateUserContextCommand.cs | 8 +--- .../src/webdriver/BiDi/Browser/UserContext.cs | 47 +------------------ .../BiDi/Network/AddDataCollectorCommand.cs | 8 +--- .../src/webdriver/BiDi/Network/Collector.cs | 43 +---------------- .../BiDi/Script/AddPreloadScriptCommand.cs | 8 +--- dotnet/src/webdriver/BiDi/Script/Handle.cs | 20 +------- .../src/webdriver/BiDi/Script/InternalId.cs | 20 +------- .../webdriver/BiDi/Script/PreloadScript.cs | 31 +----------- dotnet/src/webdriver/BiDi/Script/Realm.cs | 20 +------- .../webdriver/BiDi/WebExtension/Extension.cs | 26 +--------- .../BiDi/WebExtension/InstallCommand.cs | 8 +--- .../test/common/BiDi/Browser/BrowserTest.cs | 2 +- .../test/common/BiDi/Network/NetworkTest.cs | 4 +- .../common/BiDi/Script/ScriptCommandsTest.cs | 2 +- .../BiDi/WebExtension/WebExtensionTest.cs | 2 +- 15 files changed, 16 insertions(+), 233 deletions(-) diff --git a/dotnet/src/webdriver/BiDi/Browser/CreateUserContextCommand.cs b/dotnet/src/webdriver/BiDi/Browser/CreateUserContextCommand.cs index 59c94cca21ae2..b3331f6125b25 100644 --- a/dotnet/src/webdriver/BiDi/Browser/CreateUserContextCommand.cs +++ b/dotnet/src/webdriver/BiDi/Browser/CreateUserContextCommand.cs @@ -33,10 +33,4 @@ public sealed class CreateUserContextOptions : CommandOptions public Session.UserPromptHandler? UnhandledPromptBehavior { get; set; } } -public sealed record CreateUserContextResult(UserContext UserContext) : UserContextInfo(UserContext), IBiDiHydratable -{ - void IBiDiHydratable.Hydrate(BiDi bidi) - { - UserContext.BiDi = bidi; - } -} +public sealed record CreateUserContextResult(UserContext UserContext) : UserContextInfo(UserContext); diff --git a/dotnet/src/webdriver/BiDi/Browser/UserContext.cs b/dotnet/src/webdriver/BiDi/Browser/UserContext.cs index b3f11478d2db7..1c4dc029ed2f7 100644 --- a/dotnet/src/webdriver/BiDi/Browser/UserContext.cs +++ b/dotnet/src/webdriver/BiDi/Browser/UserContext.cs @@ -18,54 +18,9 @@ // 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 BiDi? _bidi; - - internal UserContext(string id) - { - Id = id; - } - - internal string Id { get; } - - [JsonIgnore] - public BiDi BiDi - { - get => _bidi ?? throw new InvalidOperationException($"{nameof(BiDi)} instance has not been hydrated."); - internal set => _bidi = value; - } - - public Task RemoveAsync() - { - return BiDi.Browser.RemoveUserContextAsync(this); - } - - public async ValueTask DisposeAsync() - { - await RemoveAsync().ConfigureAwait(false); - } - - public bool Equals(UserContext? other) - { - return other is not null && string.Equals(Id, other.Id, StringComparison.Ordinal); - } - - - public override bool Equals(object? obj) - { - return Equals(obj as UserContext); - } - - public override int GetHashCode() - { - return StringComparer.Ordinal.GetHashCode(Id); - } -} +public sealed record UserContext(string Id); diff --git a/dotnet/src/webdriver/BiDi/Network/AddDataCollectorCommand.cs b/dotnet/src/webdriver/BiDi/Network/AddDataCollectorCommand.cs index a6b14aa6ed8ee..ea831d1cec4c6 100644 --- a/dotnet/src/webdriver/BiDi/Network/AddDataCollectorCommand.cs +++ b/dotnet/src/webdriver/BiDi/Network/AddDataCollectorCommand.cs @@ -37,13 +37,7 @@ public class AddDataCollectorOptions : CommandOptions public IEnumerable? UserContexts { get; set; } } -public sealed record AddDataCollectorResult(Collector Collector) : EmptyResult, IBiDiHydratable -{ - void IBiDiHydratable.Hydrate(BiDi bidi) - { - Collector.BiDi = bidi; - } -} +public sealed record AddDataCollectorResult(Collector Collector) : EmptyResult; [JsonConverter(typeof(CamelCaseEnumConverter))] public enum DataType diff --git a/dotnet/src/webdriver/BiDi/Network/Collector.cs b/dotnet/src/webdriver/BiDi/Network/Collector.cs index a61e5623ba48b..7caf28b83edc8 100644 --- a/dotnet/src/webdriver/BiDi/Network/Collector.cs +++ b/dotnet/src/webdriver/BiDi/Network/Collector.cs @@ -18,50 +18,9 @@ // 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 BiDi? _bidi; - - internal Collector(string id) - { - Id = id; - } - - internal string Id { get; } - - [JsonIgnore] - public BiDi BiDi - { - get => _bidi ?? throw new InvalidOperationException($"{nameof(BiDi)} instance has not been hydrated."); - internal set => _bidi = value; - } - - public async Task RemoveAsync() - { - await BiDi.Network.RemoveDataCollectorAsync(this).ConfigureAwait(false); - } - - public async ValueTask DisposeAsync() - { - await RemoveAsync(); - } - - public override bool Equals(object? obj) - { - if (obj is Collector collectortObj) return collectortObj.Id == Id; - - return false; - } - - public override int GetHashCode() - { - return Id.GetHashCode(); - } -} +public sealed record Collector(string Id); diff --git a/dotnet/src/webdriver/BiDi/Script/AddPreloadScriptCommand.cs b/dotnet/src/webdriver/BiDi/Script/AddPreloadScriptCommand.cs index 3cbb761cab957..f01acd608504a 100644 --- a/dotnet/src/webdriver/BiDi/Script/AddPreloadScriptCommand.cs +++ b/dotnet/src/webdriver/BiDi/Script/AddPreloadScriptCommand.cs @@ -51,10 +51,4 @@ public sealed record BrowsingContextAddPreloadScriptOptions public string? Sandbox { get; set; } } -public sealed record AddPreloadScriptResult(PreloadScript Script) : EmptyResult, IBiDiHydratable -{ - void IBiDiHydratable.Hydrate(BiDi bidi) - { - Script.BiDi = bidi; - } -} +public sealed record AddPreloadScriptResult(PreloadScript Script) : EmptyResult; diff --git a/dotnet/src/webdriver/BiDi/Script/Handle.cs b/dotnet/src/webdriver/BiDi/Script/Handle.cs index 23d6e639c6220..5be7d5a8ab611 100644 --- a/dotnet/src/webdriver/BiDi/Script/Handle.cs +++ b/dotnet/src/webdriver/BiDi/Script/Handle.cs @@ -18,27 +18,9 @@ // using OpenQA.Selenium.BiDi.Json.Converters; -using System; using System.Text.Json.Serialization; namespace OpenQA.Selenium.BiDi.Script; [JsonConverter(typeof(HandleConverter))] -public sealed class Handle -{ - private BiDi? _bidi; - - public Handle(string id) - { - Id = id; - } - - public string Id { get; } - - [JsonIgnore] - public BiDi BiDi - { - get => _bidi ?? throw new InvalidOperationException($"{nameof(BiDi)} instance has not been hydrated."); - internal set => _bidi = value; - } -} +public sealed record Handle(string Id); diff --git a/dotnet/src/webdriver/BiDi/Script/InternalId.cs b/dotnet/src/webdriver/BiDi/Script/InternalId.cs index 1b8c9f1820123..260288d08bb3f 100644 --- a/dotnet/src/webdriver/BiDi/Script/InternalId.cs +++ b/dotnet/src/webdriver/BiDi/Script/InternalId.cs @@ -18,27 +18,9 @@ // using OpenQA.Selenium.BiDi.Json.Converters; -using System; using System.Text.Json.Serialization; namespace OpenQA.Selenium.BiDi.Script; [JsonConverter(typeof(InternalIdConverter))] -public sealed class InternalId -{ - public InternalId(string id) - { - Id = id; - } - - public string Id { get; } - - private BiDi? _bidi; - - [JsonIgnore] - public BiDi BiDi - { - get => _bidi ?? throw new InvalidOperationException($"{nameof(BiDi)} instance has not been hydrated."); - internal set => _bidi = value; - } -} +public sealed record InternalId(string Id); diff --git a/dotnet/src/webdriver/BiDi/Script/PreloadScript.cs b/dotnet/src/webdriver/BiDi/Script/PreloadScript.cs index 15af12f727bdc..0b088b7023a2a 100644 --- a/dotnet/src/webdriver/BiDi/Script/PreloadScript.cs +++ b/dotnet/src/webdriver/BiDi/Script/PreloadScript.cs @@ -18,38 +18,9 @@ // 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 BiDi? _bidi; - - internal PreloadScript(string id) - { - Id = id; - } - - public string Id { get; } - - [JsonIgnore] - public BiDi BiDi - { - get => _bidi ?? throw new InvalidOperationException($"{nameof(BiDi)} instance has not been hydrated."); - internal set => _bidi = value; - } - - public Task RemoveAsync() - { - return BiDi.Script.RemovePreloadScriptAsync(this); - } - - public async ValueTask DisposeAsync() - { - await RemoveAsync().ConfigureAwait(false); - } -} +public sealed record PreloadScript(string Id); diff --git a/dotnet/src/webdriver/BiDi/Script/Realm.cs b/dotnet/src/webdriver/BiDi/Script/Realm.cs index 17e1f8b296e22..0385a1747d4f5 100644 --- a/dotnet/src/webdriver/BiDi/Script/Realm.cs +++ b/dotnet/src/webdriver/BiDi/Script/Realm.cs @@ -18,27 +18,9 @@ // using OpenQA.Selenium.BiDi.Json.Converters; -using System; using System.Text.Json.Serialization; namespace OpenQA.Selenium.BiDi.Script; [JsonConverter(typeof(RealmConverter))] -public sealed class Realm -{ - public Realm(string id) - { - Id = id; - } - - public string Id { get; } - - private BiDi? _bidi; - - [JsonIgnore] - public BiDi BiDi - { - get => _bidi ?? throw new InvalidOperationException($"{nameof(BiDi)} instance has not been hydrated."); - internal set => _bidi = value; - } -} +public sealed record Realm(string Id); diff --git a/dotnet/src/webdriver/BiDi/WebExtension/Extension.cs b/dotnet/src/webdriver/BiDi/WebExtension/Extension.cs index f44b1419d9797..7e1b78f38fa8e 100644 --- a/dotnet/src/webdriver/BiDi/WebExtension/Extension.cs +++ b/dotnet/src/webdriver/BiDi/WebExtension/Extension.cs @@ -18,33 +18,9 @@ // using OpenQA.Selenium.BiDi.Json.Converters; -using System; using System.Text.Json.Serialization; -using System.Threading.Tasks; namespace OpenQA.Selenium.BiDi.WebExtension; [JsonConverter(typeof(WebExtensionConverter))] -public sealed class Extension -{ - private BiDi? _bidi; - - internal Extension(string id) - { - Id = id; - } - - internal string Id { get; } - - [JsonIgnore] - public BiDi BiDi - { - get => _bidi ?? throw new InvalidOperationException($"{nameof(BiDi)} instance has not been hydrated."); - internal set => _bidi = value; - } - - public Task UninstallAsync(UninstallOptions? options = null) - { - return BiDi.WebExtension.UninstallAsync(this, options); - } -} +public sealed record Extension(string Id); diff --git a/dotnet/src/webdriver/BiDi/WebExtension/InstallCommand.cs b/dotnet/src/webdriver/BiDi/WebExtension/InstallCommand.cs index 4fa8a134ca346..d7c4e29d3d756 100644 --- a/dotnet/src/webdriver/BiDi/WebExtension/InstallCommand.cs +++ b/dotnet/src/webdriver/BiDi/WebExtension/InstallCommand.cs @@ -41,10 +41,4 @@ public sealed record ExtensionPath(string Path) : ExtensionData; public sealed class InstallOptions : CommandOptions; -public sealed record InstallResult(Extension Extension) : EmptyResult, IBiDiHydratable -{ - void IBiDiHydratable.Hydrate(BiDi bidi) - { - Extension.BiDi = bidi; - } -} +public sealed record InstallResult(Extension Extension) : EmptyResult; diff --git a/dotnet/test/common/BiDi/Browser/BrowserTest.cs b/dotnet/test/common/BiDi/Browser/BrowserTest.cs index 39c4686b60124..44f4309850fce 100644 --- a/dotnet/test/common/BiDi/Browser/BrowserTest.cs +++ b/dotnet/test/common/BiDi/Browser/BrowserTest.cs @@ -53,7 +53,7 @@ public async Task CanRemoveUserContext() var userContext1 = await bidi.Browser.CreateUserContextAsync(); var userContext2 = await bidi.Browser.CreateUserContextAsync(); - await userContext2.UserContext.RemoveAsync(); + await bidi.Browser.RemoveUserContextAsync(userContext2.UserContext); var userContextsResult = await bidi.Browser.GetUserContextsAsync(); diff --git a/dotnet/test/common/BiDi/Network/NetworkTest.cs b/dotnet/test/common/BiDi/Network/NetworkTest.cs index 577e79a419515..25c46a33b8eca 100644 --- a/dotnet/test/common/BiDi/Network/NetworkTest.cs +++ b/dotnet/test/common/BiDi/Network/NetworkTest.cs @@ -31,7 +31,7 @@ public async Task CanAddDataCollector() { // Firefox doesn't like int.MaxValue as max encoded data size // invalid argument: Expected "maxEncodedDataSize" to be less than the max total data size available (200000000), got 2147483647 - await using var collector = await bidi.Network.AddDataCollectorAsync([DataType.Response], 200000000); + var collector = await bidi.Network.AddDataCollectorAsync([DataType.Response], 200000000); Assert.That(collector, Is.Not.Null); } @@ -226,7 +226,7 @@ public async Task CanGetData() { // Firefox doesn't like int.MaxValue as max encoded data size // invalid argument: Expected "maxEncodedDataSize" to be less than the max total data size available (200000000), got 2147483647 - await using var collector = await bidi.Network.AddDataCollectorAsync([DataType.Response], 200000000); + var collector = await bidi.Network.AddDataCollectorAsync([DataType.Response], 200000000); TaskCompletionSource responseBodyCompletionSource = new(); diff --git a/dotnet/test/common/BiDi/Script/ScriptCommandsTest.cs b/dotnet/test/common/BiDi/Script/ScriptCommandsTest.cs index e21b1748681c5..f12882bf7128b 100644 --- a/dotnet/test/common/BiDi/Script/ScriptCommandsTest.cs +++ b/dotnet/test/common/BiDi/Script/ScriptCommandsTest.cs @@ -159,7 +159,7 @@ public async Task CanRemovePreloadedScript() Assert.That(bar, Is.EqualTo(2)); - await preloadScript.Script.RemoveAsync(); + await bidi.Script.RemovePreloadScriptAsync(preloadScript.Script); var resultAfterRemoval = await context.Script.EvaluateAsync("window.bar", true, targetOptions: new() { Sandbox = "sandbox" }); diff --git a/dotnet/test/common/BiDi/WebExtension/WebExtensionTest.cs b/dotnet/test/common/BiDi/WebExtension/WebExtensionTest.cs index 5065abe2554be..19f1c8464ecbe 100644 --- a/dotnet/test/common/BiDi/WebExtension/WebExtensionTest.cs +++ b/dotnet/test/common/BiDi/WebExtension/WebExtensionTest.cs @@ -81,7 +81,7 @@ public async Task CanUninstallExtension() var result = await bidi.WebExtension.InstallAsync(new ExtensionPath(path)); - await result.Extension.UninstallAsync(); + await bidi.WebExtension.UninstallAsync(result.Extension); } private static string LocateRelativePath(string path) From d1a2fcb9482ee74a5d3e570c117f9fb4f04d0553 Mon Sep 17 00:00:00 2001 From: Nikolay Borisenko <22616990+nvborisenko@users.noreply.github.com> Date: Wed, 3 Dec 2025 21:54:24 +0300 Subject: [PATCH 16/16] High level interception is not hydratable --- .../BrowsingContextNetworkModule.cs | 30 +++-- .../BiDi/Network/AddInterceptCommand.cs | 8 +- .../src/webdriver/BiDi/Network/Intercept.cs | 109 +----------------- .../BiDi/Network/NetworkModule.HighLevel.cs | 108 +++++++++++++++-- .../webdriver/BiDi/Network/NetworkModule.cs | 6 +- 5 files changed, 118 insertions(+), 143 deletions(-) diff --git a/dotnet/src/webdriver/BiDi/BrowsingContext/BrowsingContextNetworkModule.cs b/dotnet/src/webdriver/BiDi/BrowsingContext/BrowsingContextNetworkModule.cs index 2caf06632cc9c..14e6b43ca4bac 100644 --- a/dotnet/src/webdriver/BiDi/BrowsingContext/BrowsingContextNetworkModule.cs +++ b/dotnet/src/webdriver/BiDi/BrowsingContext/BrowsingContextNetworkModule.cs @@ -25,52 +25,58 @@ namespace OpenQA.Selenium.BiDi.BrowsingContext; public sealed class BrowsingContextNetworkModule(BrowsingContext context, NetworkModule networkModule) { - public async Task InterceptRequestAsync(Func handler, InterceptRequestOptions? options = null) + public async Task InterceptRequestAsync(Func handler, InterceptRequestOptions? options = null) { AddInterceptOptions addInterceptOptions = new(options) { Contexts = [context] }; - var intercept = await networkModule.AddInterceptAsync([InterceptPhase.BeforeRequestSent], addInterceptOptions).ConfigureAwait(false); + var interceptResult = await networkModule.AddInterceptAsync([InterceptPhase.BeforeRequestSent], addInterceptOptions).ConfigureAwait(false); - await intercept.OnBeforeRequestSentAsync( + Interception interception = new(context.BiDi, interceptResult.Intercept); + + await interception.OnBeforeRequestSentAsync( async req => await handler(new(req.BiDi, req.Context, req.IsBlocked, req.Navigation, req.RedirectCount, req.Request, req.Timestamp, req.Initiator, req.Intercepts)), new() { Contexts = [context] }).ConfigureAwait(false); - return intercept; + return interception; } - public async Task InterceptResponseAsync(Func handler, InterceptResponseOptions? options = null) + public async Task InterceptResponseAsync(Func handler, InterceptResponseOptions? options = null) { AddInterceptOptions addInterceptOptions = new(options) { Contexts = [context] }; - var intercept = await networkModule.AddInterceptAsync([InterceptPhase.ResponseStarted], addInterceptOptions).ConfigureAwait(false); + var interceptResult = await networkModule.AddInterceptAsync([InterceptPhase.ResponseStarted], addInterceptOptions).ConfigureAwait(false); + + Interception interception = new(context.BiDi, interceptResult.Intercept); - await intercept.OnResponseStartedAsync( + await interception.OnResponseStartedAsync( async res => await handler(new(res.BiDi, res.Context, res.IsBlocked, res.Navigation, res.RedirectCount, res.Request, res.Timestamp, res.Response, res.Intercepts)), new() { Contexts = [context] }).ConfigureAwait(false); - return intercept; + return interception; } - public async Task InterceptAuthAsync(Func handler, InterceptAuthOptions? options = null) + public async Task InterceptAuthAsync(Func handler, InterceptAuthOptions? options = null) { AddInterceptOptions addInterceptOptions = new(options) { Contexts = [context] }; - var intercept = await networkModule.AddInterceptAsync([InterceptPhase.AuthRequired], addInterceptOptions).ConfigureAwait(false); + var interceptResult = await networkModule.AddInterceptAsync([InterceptPhase.AuthRequired], addInterceptOptions).ConfigureAwait(false); + + Interception interception = new(context.BiDi, interceptResult.Intercept); - await intercept.OnAuthRequiredAsync( + await interception.OnAuthRequiredAsync( async auth => await handler(new(auth.BiDi, auth.Context, auth.IsBlocked, auth.Navigation, auth.RedirectCount, auth.Request, auth.Timestamp, auth.Response, auth.Intercepts)), new() { Contexts = [context] }).ConfigureAwait(false); - return intercept; + return interception; } public Task SetCacheBehaviorAsync(CacheBehavior behavior, BrowsingContextSetCacheBehaviorOptions? options = null) diff --git a/dotnet/src/webdriver/BiDi/Network/AddInterceptCommand.cs b/dotnet/src/webdriver/BiDi/Network/AddInterceptCommand.cs index 043a299bc3e51..23055edfa82fe 100644 --- a/dotnet/src/webdriver/BiDi/Network/AddInterceptCommand.cs +++ b/dotnet/src/webdriver/BiDi/Network/AddInterceptCommand.cs @@ -47,13 +47,7 @@ public record BrowsingContextAddInterceptOptions public IEnumerable? UrlPatterns { get; set; } } -public sealed record AddInterceptResult(Intercept Intercept) : EmptyResult, IBiDiHydratable -{ - void IBiDiHydratable.Hydrate(BiDi bidi) - { - Intercept.BiDi = bidi; - } -} +public sealed record AddInterceptResult(Intercept Intercept) : EmptyResult; [JsonConverter(typeof(CamelCaseEnumConverter))] public enum InterceptPhase diff --git a/dotnet/src/webdriver/BiDi/Network/Intercept.cs b/dotnet/src/webdriver/BiDi/Network/Intercept.cs index 3bf49a99d1e84..dbb43aad377b9 100644 --- a/dotnet/src/webdriver/BiDi/Network/Intercept.cs +++ b/dotnet/src/webdriver/BiDi/Network/Intercept.cs @@ -18,116 +18,9 @@ // 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 BiDi? _bidi; - - internal Intercept(string id) - { - Id = id; - } - - internal string Id { get; } - - [JsonIgnore] - public BiDi BiDi - { - get => _bidi ?? throw new InvalidOperationException($"{nameof(BiDi)} instance has not been hydrated."); - internal set => _bidi = value; - } - - IList OnBeforeRequestSentSubscriptions { get; } = []; - IList OnResponseStartedSubscriptions { get; } = []; - IList OnAuthRequiredSubscriptions { get; } = []; - - public async Task RemoveAsync() - { - await BiDi.Network.RemoveInterceptAsync(this).ConfigureAwait(false); - - foreach (var subscription in OnBeforeRequestSentSubscriptions) - { - await subscription.UnsubscribeAsync().ConfigureAwait(false); - } - - foreach (var subscription in OnResponseStartedSubscriptions) - { - await subscription.UnsubscribeAsync().ConfigureAwait(false); - } - - foreach (var subscription in OnAuthRequiredSubscriptions) - { - await subscription.UnsubscribeAsync().ConfigureAwait(false); - } - } - - public async Task OnBeforeRequestSentAsync(Func handler, SubscriptionOptions? options = null) - { - var subscription = await BiDi.Network.OnBeforeRequestSentAsync(async args => await Filter(args, handler), options).ConfigureAwait(false); - - OnBeforeRequestSentSubscriptions.Add(subscription); - } - - public async Task OnResponseStartedAsync(Func handler, SubscriptionOptions? options = null) - { - var subscription = await BiDi.Network.OnResponseStartedAsync(async args => await Filter(args, handler), options).ConfigureAwait(false); - - OnResponseStartedSubscriptions.Add(subscription); - } - - public async Task OnAuthRequiredAsync(Func handler, SubscriptionOptions? options = null) - { - var subscription = await BiDi.Network.OnAuthRequiredAsync(async args => await Filter(args, handler), options).ConfigureAwait(false); - - OnAuthRequiredSubscriptions.Add(subscription); - } - - private async Task Filter(BeforeRequestSentEventArgs args, Func handler) - { - if (args.Intercepts?.Contains(this) is true && args.IsBlocked) - { - await handler(args).ConfigureAwait(false); - } - } - - private async Task Filter(ResponseStartedEventArgs args, Func handler) - { - if (args.Intercepts?.Contains(this) is true && args.IsBlocked) - { - await handler(args).ConfigureAwait(false); - } - } - - private async Task Filter(AuthRequiredEventArgs args, Func handler) - { - if (args.Intercepts?.Contains(this) is true && args.IsBlocked) - { - await handler(args).ConfigureAwait(false); - } - } - - public async ValueTask DisposeAsync() - { - await RemoveAsync(); - } - - public override bool Equals(object? obj) - { - if (obj is Intercept interceptObj) return interceptObj.Id == Id; - - return false; - } - - public override int GetHashCode() - { - return Id.GetHashCode(); - } -} +public sealed record Intercept(string Id); diff --git a/dotnet/src/webdriver/BiDi/Network/NetworkModule.HighLevel.cs b/dotnet/src/webdriver/BiDi/Network/NetworkModule.HighLevel.cs index 58b9dfc4cd091..54324e11cf8f2 100644 --- a/dotnet/src/webdriver/BiDi/Network/NetworkModule.HighLevel.cs +++ b/dotnet/src/webdriver/BiDi/Network/NetworkModule.HighLevel.cs @@ -19,37 +19,44 @@ using System; using System.Collections.Generic; +using System.Linq; using System.Threading.Tasks; namespace OpenQA.Selenium.BiDi.Network; public partial class NetworkModule { - public async Task InterceptRequestAsync(Func handler, InterceptRequestOptions? options = null) + public async Task InterceptRequestAsync(Func handler, InterceptRequestOptions? options = null) { - var intercept = await AddInterceptAsync([InterceptPhase.BeforeRequestSent], options).ConfigureAwait(false); + var interceptResult = await AddInterceptAsync([InterceptPhase.BeforeRequestSent], options).ConfigureAwait(false); - await intercept.OnBeforeRequestSentAsync(async req => await handler(new(req.BiDi, req.Context, req.IsBlocked, req.Navigation, req.RedirectCount, req.Request, req.Timestamp, req.Initiator, req.Intercepts))).ConfigureAwait(false); + Interception interception = new(BiDi, interceptResult.Intercept); - return intercept; + await interception.OnBeforeRequestSentAsync(async req => await handler(new(req.BiDi, req.Context, req.IsBlocked, req.Navigation, req.RedirectCount, req.Request, req.Timestamp, req.Initiator, req.Intercepts))).ConfigureAwait(false); + + return interception; } - public async Task InterceptResponseAsync(Func handler, InterceptResponseOptions? options = null) + public async Task InterceptResponseAsync(Func handler, InterceptResponseOptions? options = null) { - var intercept = await AddInterceptAsync([InterceptPhase.ResponseStarted], options).ConfigureAwait(false); + var interceptResult = await AddInterceptAsync([InterceptPhase.ResponseStarted], options).ConfigureAwait(false); + + Interception interception = new(BiDi, interceptResult.Intercept); - await intercept.OnResponseStartedAsync(async res => await handler(new(res.BiDi, res.Context, res.IsBlocked, res.Navigation, res.RedirectCount, res.Request, res.Timestamp, res.Response, res.Intercepts))).ConfigureAwait(false); + await interception.OnResponseStartedAsync(async res => await handler(new(res.BiDi, res.Context, res.IsBlocked, res.Navigation, res.RedirectCount, res.Request, res.Timestamp, res.Response, res.Intercepts))).ConfigureAwait(false); - return intercept; + return interception; } - public async Task InterceptAuthAsync(Func handler, InterceptAuthOptions? options = null) + public async Task InterceptAuthAsync(Func handler, InterceptAuthOptions? options = null) { - var intercept = await AddInterceptAsync([InterceptPhase.AuthRequired], options).ConfigureAwait(false); + var interceptResult = await AddInterceptAsync([InterceptPhase.AuthRequired], options).ConfigureAwait(false); + + Interception interception = new(BiDi, interceptResult.Intercept); - await intercept.OnAuthRequiredAsync(async auth => await handler(new(auth.BiDi, auth.Context, auth.IsBlocked, auth.Navigation, auth.RedirectCount, auth.Request, auth.Timestamp, auth.Response, auth.Intercepts))).ConfigureAwait(false); + await interception.OnAuthRequiredAsync(async auth => await handler(new(auth.BiDi, auth.Context, auth.IsBlocked, auth.Navigation, auth.RedirectCount, auth.Request, auth.Timestamp, auth.Response, auth.Intercepts))).ConfigureAwait(false); - return intercept; + return interception; } } @@ -120,3 +127,80 @@ public Task ContinueAsync(ContinueWithAuthCancelCredentialsOptions? options = nu return BiDi.Network.ContinueWithAuthAsync(Request.Request, options); } } + +public sealed record Interception(BiDi BiDi, Intercept Intercept) : IAsyncDisposable +{ + IList OnBeforeRequestSentSubscriptions { get; } = []; + IList OnResponseStartedSubscriptions { get; } = []; + IList OnAuthRequiredSubscriptions { get; } = []; + + public async Task RemoveAsync() + { + await BiDi.Network.RemoveInterceptAsync(Intercept).ConfigureAwait(false); + + foreach (var subscription in OnBeforeRequestSentSubscriptions) + { + await subscription.UnsubscribeAsync().ConfigureAwait(false); + } + + foreach (var subscription in OnResponseStartedSubscriptions) + { + await subscription.UnsubscribeAsync().ConfigureAwait(false); + } + + foreach (var subscription in OnAuthRequiredSubscriptions) + { + await subscription.UnsubscribeAsync().ConfigureAwait(false); + } + } + + public async Task OnBeforeRequestSentAsync(Func handler, SubscriptionOptions? options = null) + { + var subscription = await BiDi.Network.OnBeforeRequestSentAsync(async args => await Filter(args, handler), options).ConfigureAwait(false); + + OnBeforeRequestSentSubscriptions.Add(subscription); + } + + public async Task OnResponseStartedAsync(Func handler, SubscriptionOptions? options = null) + { + var subscription = await BiDi.Network.OnResponseStartedAsync(async args => await Filter(args, handler), options).ConfigureAwait(false); + + OnResponseStartedSubscriptions.Add(subscription); + } + + public async Task OnAuthRequiredAsync(Func handler, SubscriptionOptions? options = null) + { + var subscription = await BiDi.Network.OnAuthRequiredAsync(async args => await Filter(args, handler), options).ConfigureAwait(false); + + OnAuthRequiredSubscriptions.Add(subscription); + } + + private async Task Filter(BeforeRequestSentEventArgs args, Func handler) + { + if (args.Intercepts?.Contains(Intercept) is true && args.IsBlocked) + { + await handler(args).ConfigureAwait(false); + } + } + + private async Task Filter(ResponseStartedEventArgs args, Func handler) + { + if (args.Intercepts?.Contains(Intercept) is true && args.IsBlocked) + { + await handler(args).ConfigureAwait(false); + } + } + + private async Task Filter(AuthRequiredEventArgs args, Func handler) + { + if (args.Intercepts?.Contains(Intercept) is true && args.IsBlocked) + { + await handler(args).ConfigureAwait(false); + } + } + + public async ValueTask DisposeAsync() + { + await RemoveAsync().ConfigureAwait(false); + } +} diff --git a/dotnet/src/webdriver/BiDi/Network/NetworkModule.cs b/dotnet/src/webdriver/BiDi/Network/NetworkModule.cs index 0a9aaa3357529..172e0943ad2bc 100644 --- a/dotnet/src/webdriver/BiDi/Network/NetworkModule.cs +++ b/dotnet/src/webdriver/BiDi/Network/NetworkModule.cs @@ -38,13 +38,11 @@ public async Task AddDataCollectorAsync(IEnumerable DataTyp return result.Collector; } - public async Task AddInterceptAsync(IEnumerable phases, AddInterceptOptions? options = null) + public async Task AddInterceptAsync(IEnumerable phases, AddInterceptOptions? options = null) { var @params = new AddInterceptParameters(phases, options?.Contexts, options?.UrlPatterns); - var result = await Broker.ExecuteCommandAsync(new AddInterceptCommand(@params), options, _jsonContext.AddInterceptCommand, _jsonContext.AddInterceptResult).ConfigureAwait(false); - - return result.Intercept; + return await Broker.ExecuteCommandAsync(new AddInterceptCommand(@params), options, _jsonContext.AddInterceptCommand, _jsonContext.AddInterceptResult).ConfigureAwait(false); } public async Task RemoveDataCollectorAsync(Collector collector, RemoveDataCollectorOptions? options = null)