Skip to content

Commit cfa5401

Browse files
committed
Separate DevTools JSON serialization context per domain
1 parent 7f122e8 commit cfa5401

File tree

13 files changed

+209
-31
lines changed

13 files changed

+209
-31
lines changed

dotnet/src/webdriver/DevTools/DevToolsDomains.cs

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,8 @@
2020
using System;
2121
using System.Collections.Generic;
2222
using System.Reflection;
23+
using System.Text.Json;
24+
using System.Text.Json.Nodes;
2325

2426
namespace OpenQA.Selenium.DevTools
2527
{
@@ -68,6 +70,15 @@ public abstract class DevToolsDomains
6870
/// </summary>
6971
public abstract Log Log { get; }
7072

73+
internal abstract JsonNode SerializeToNode<TCommand>(TCommand command)
74+
where TCommand : ICommand;
75+
76+
internal abstract ICommandResponse<TCommand> DeserializeCommandResponse<TCommand>(JsonElement responseJson)
77+
where TCommand : ICommand;
78+
79+
internal abstract TCommandResponse Deserialize<TCommandResponse>(JsonElement responseJson)
80+
where TCommandResponse : ICommandResponse;
81+
7182
/// <summary>
7283
/// Initializes the supplied DevTools session's domains for the specified browser version.
7384
/// </summary>

dotnet/src/webdriver/DevTools/DevToolsSession.cs

Lines changed: 12 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -61,11 +61,6 @@ public class DevToolsSession : IDevToolsSession
6161

6262
private readonly static ILogger logger = Internal.Logging.Log.GetLogger<DevToolsSession>();
6363

64-
private static readonly JsonSerializerOptions s_devToolsSerializerOptions = new()
65-
{
66-
TypeInfoResolver = CdpSerializationContext.Default,
67-
};
68-
6964
/// <summary>
7065
/// Initializes a new instance of the DevToolsSession class, using the specified WebSocket endpoint.
7166
/// </summary>
@@ -162,19 +157,16 @@ public T GetVersionSpecificDomains<T>() where T : DevToolsSessionDomains
162157
throw new ArgumentNullException(nameof(command));
163158
}
164159

165-
var result = await SendCommand(command.CommandName, JsonSerializer.SerializeToNode(command), cancellationToken, millisecondsTimeout, throwExceptionIfResponseNotReceived).ConfigureAwait(false);
160+
JsonNode serializedCommand = this.domains.SerializeToNode(command);
161+
162+
var result = await SendCommand(command.CommandName, serializedCommand, cancellationToken, millisecondsTimeout, throwExceptionIfResponseNotReceived).ConfigureAwait(false);
166163

167164
if (result == null)
168165
{
169166
return null;
170167
}
171168

172-
if (!this.domains.VersionSpecificDomains.ResponseTypeMap.TryGetCommandResponseType<TCommand>(out Type commandResponseType))
173-
{
174-
throw new InvalidOperationException($"Type {command.GetType()} does not correspond to a known command response type.");
175-
}
176-
177-
return result.Value.Deserialize(commandResponseType) as ICommandResponse<TCommand>;
169+
return this.domains.DeserializeCommandResponse<TCommand>(result.Value);
178170
}
179171

180172
/// <summary>
@@ -195,19 +187,16 @@ public T GetVersionSpecificDomains<T>() where T : DevToolsSessionDomains
195187
throw new ArgumentNullException(nameof(command));
196188
}
197189

198-
var result = await SendCommand(command.CommandName, sessionId, JsonSerializer.SerializeToNode(command, s_devToolsSerializerOptions), cancellationToken, millisecondsTimeout, throwExceptionIfResponseNotReceived).ConfigureAwait(false);
190+
JsonNode serializedCommand = this.domains.SerializeToNode(command);
191+
192+
var result = await SendCommand(command.CommandName, sessionId, serializedCommand, cancellationToken, millisecondsTimeout, throwExceptionIfResponseNotReceived).ConfigureAwait(false);
199193

200194
if (result == null)
201195
{
202196
return null;
203197
}
204198

205-
if (!this.domains.VersionSpecificDomains.ResponseTypeMap.TryGetCommandResponseType(command, out Type commandResponseType))
206-
{
207-
throw new InvalidOperationException($"Type {typeof(TCommand)} does not correspond to a known command response type.");
208-
}
209-
210-
return (ICommandResponse<TCommand>)result.Value.Deserialize(commandResponseType, s_devToolsSerializerOptions);
199+
return this.domains.DeserializeCommandResponse<TCommand>(result.Value);
211200
}
212201

213202
/// <summary>
@@ -229,14 +218,16 @@ public T GetVersionSpecificDomains<T>() where T : DevToolsSessionDomains
229218
throw new ArgumentNullException(nameof(command));
230219
}
231220

232-
var result = await SendCommand(command.CommandName, JsonSerializer.SerializeToNode(command), cancellationToken, millisecondsTimeout, throwExceptionIfResponseNotReceived).ConfigureAwait(false);
221+
JsonNode serializedCommand = this.domains.SerializeToNode(command);
222+
223+
var result = await SendCommand(command.CommandName, serializedCommand, cancellationToken, millisecondsTimeout, throwExceptionIfResponseNotReceived).ConfigureAwait(false);
233224

234225
if (result == null)
235226
{
236227
return default(TCommandResponse);
237228
}
238229

239-
return result.Value.Deserialize<TCommandResponse>();
230+
return this.domains.Deserialize<TCommandResponse>(result.Value);
240231
}
241232

242233
/// <summary>
Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
1-
using System.Text.Json.Serialization;
1+
// using System.Text.Json.Serialization;
22

3-
namespace OpenQA.Selenium.DevTools.Json;
3+
// namespace OpenQA.Selenium.DevTools.Json;
44

5-
[JsonSerializable(typeof(ICommand))]
6-
[JsonSerializable(typeof(ICommandResponse<>))]
7-
[JsonSourceGenerationOptions(Converters = [typeof(StringConverter)])]
8-
internal sealed partial class CdpSerializationContext : JsonSerializerContext;
5+
// [JsonSerializable(typeof(ICommand))]
6+
// [JsonSerializable(typeof(ICommandResponse<>))]
7+
// [JsonSourceGenerationOptions(Converters = [typeof(StringConverter)])]
8+
// internal sealed partial class CdpSerializationContext : JsonSerializerContext;
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
using System.Text.Json.Serialization;
2+
3+
namespace OpenQA.Selenium.DevTools.V130;
4+
5+
[JsonSerializable(typeof(ICommand))]
6+
internal sealed partial class V130RequestSerializationContext : JsonSerializerContext;
7+
8+
[JsonSerializable(typeof(ICommand))]
9+
internal sealed partial class V130ResponseSerializationContext : JsonSerializerContext;

dotnet/src/webdriver/DevTools/v130/V130Domains.cs

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,13 +17,27 @@
1717
// under the License.
1818
// </copyright>
1919

20+
using System;
21+
using System.Text.Json;
22+
using System.Text.Json.Nodes;
23+
2024
namespace OpenQA.Selenium.DevTools.V130
2125
{
2226
/// <summary>
2327
/// Class containing the domain implementation for version 130 of the DevTools Protocol.
2428
/// </summary>
2529
public class V130Domains : DevToolsDomains
2630
{
31+
private static readonly JsonSerializerOptions jsonRequestSerializerOptions = new()
32+
{
33+
TypeInfoResolver = V130RequestSerializationContext.Default
34+
};
35+
36+
private static readonly JsonSerializerOptions jsonResponseSerializerOptions = new()
37+
{
38+
TypeInfoResolver = V130ResponseSerializationContext.Default
39+
};
40+
2741
private DevToolsSessionDomains domains;
2842

2943
/// <summary>
@@ -64,5 +78,25 @@ public V130Domains(DevToolsSession session)
6478
/// Gets the object used for manipulating the browser's logs.
6579
/// </summary>
6680
public override DevTools.Log Log => new V130Log(domains.Log);
81+
82+
internal override JsonNode SerializeToNode<TCommand>(TCommand command)
83+
{
84+
return JsonSerializer.SerializeToNode(command, jsonRequestSerializerOptions);
85+
}
86+
87+
internal override ICommandResponse<TCommand> DeserializeCommandResponse<TCommand>(JsonElement responseJson)
88+
{
89+
if (!this.VersionSpecificDomains.ResponseTypeMap.TryGetCommandResponseType<TCommand>(out Type commandResponseType))
90+
{
91+
throw new InvalidOperationException($"Type {typeof(TCommand)} does not correspond to a known command response type.");
92+
}
93+
94+
return (ICommandResponse<TCommand>)responseJson.Deserialize(commandResponseType, jsonResponseSerializerOptions);
95+
}
96+
97+
internal override TCommandResponse Deserialize<TCommandResponse>(JsonElement responseJson)
98+
{
99+
return responseJson.Deserialize<TCommandResponse>(jsonResponseSerializerOptions);
100+
}
67101
}
68102
}
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
using System.Text.Json.Serialization;
2+
3+
namespace OpenQA.Selenium.DevTools.V131;
4+
5+
[JsonSerializable(typeof(ICommand))]
6+
internal sealed partial class V131RequestSerializationContext : JsonSerializerContext;
7+
8+
[JsonSerializable(typeof(ICommand))]
9+
internal sealed partial class V131ResponseSerializationContext : JsonSerializerContext;

dotnet/src/webdriver/DevTools/v131/V131Domains.cs

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,13 +17,27 @@
1717
// under the License.
1818
// </copyright>
1919

20+
using System;
21+
using System.Text.Json;
22+
using System.Text.Json.Nodes;
23+
2024
namespace OpenQA.Selenium.DevTools.V131
2125
{
2226
/// <summary>
2327
/// Class containing the domain implementation for version 131 of the DevTools Protocol.
2428
/// </summary>
2529
public class V131Domains : DevToolsDomains
2630
{
31+
private static readonly JsonSerializerOptions jsonRequestSerializerOptions = new()
32+
{
33+
TypeInfoResolver = V131RequestSerializationContext.Default
34+
};
35+
36+
private static readonly JsonSerializerOptions jsonResponseSerializerOptions = new()
37+
{
38+
TypeInfoResolver = V131ResponseSerializationContext.Default
39+
};
40+
2741
private DevToolsSessionDomains domains;
2842

2943
/// <summary>
@@ -64,5 +78,25 @@ public V131Domains(DevToolsSession session)
6478
/// Gets the object used for manipulating the browser's logs.
6579
/// </summary>
6680
public override DevTools.Log Log => new V131Log(domains.Log);
81+
82+
internal override JsonNode SerializeToNode<TCommand>(TCommand command)
83+
{
84+
return JsonSerializer.SerializeToNode(command, jsonRequestSerializerOptions);
85+
}
86+
87+
internal override ICommandResponse<TCommand> DeserializeCommandResponse<TCommand>(JsonElement responseJson)
88+
{
89+
if (!this.VersionSpecificDomains.ResponseTypeMap.TryGetCommandResponseType<TCommand>(out Type commandResponseType))
90+
{
91+
throw new InvalidOperationException($"Type {typeof(TCommand)} does not correspond to a known command response type.");
92+
}
93+
94+
return (ICommandResponse<TCommand>)responseJson.Deserialize(commandResponseType, jsonResponseSerializerOptions);
95+
}
96+
97+
internal override TCommandResponse Deserialize<TCommandResponse>(JsonElement responseJson)
98+
{
99+
return responseJson.Deserialize<TCommandResponse>(jsonResponseSerializerOptions);
100+
}
67101
}
68102
}
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
using System.Text.Json.Serialization;
2+
3+
namespace OpenQA.Selenium.DevTools.V132;
4+
5+
[JsonSerializable(typeof(ICommand))]
6+
internal sealed partial class V132RequestSerializationContext : JsonSerializerContext;
7+
8+
[JsonSerializable(typeof(ICommand))]
9+
internal sealed partial class V132ResponseSerializationContext : JsonSerializerContext;

dotnet/src/webdriver/DevTools/v132/V132Domains.cs

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,13 +17,27 @@
1717
// under the License.
1818
// </copyright>
1919

20+
using System;
21+
using System.Text.Json;
22+
using System.Text.Json.Nodes;
23+
2024
namespace OpenQA.Selenium.DevTools.V132
2125
{
2226
/// <summary>
2327
/// Class containing the domain implementation for version 132 of the DevTools Protocol.
2428
/// </summary>
2529
public class V132Domains : DevToolsDomains
2630
{
31+
private static readonly JsonSerializerOptions jsonRequestSerializerOptions = new()
32+
{
33+
TypeInfoResolver = V132RequestSerializationContext.Default
34+
};
35+
36+
private static readonly JsonSerializerOptions jsonResponseSerializerOptions = new()
37+
{
38+
TypeInfoResolver = V132ResponseSerializationContext.Default
39+
};
40+
2741
private DevToolsSessionDomains domains;
2842

2943
/// <summary>
@@ -64,5 +78,25 @@ public V132Domains(DevToolsSession session)
6478
/// Gets the object used for manipulating the browser's logs.
6579
/// </summary>
6680
public override DevTools.Log Log => new V132Log(domains.Log);
81+
82+
internal override JsonNode SerializeToNode<TCommand>(TCommand command)
83+
{
84+
return JsonSerializer.SerializeToNode(command, jsonRequestSerializerOptions);
85+
}
86+
87+
internal override ICommandResponse<TCommand> DeserializeCommandResponse<TCommand>(JsonElement responseJson)
88+
{
89+
if (!this.VersionSpecificDomains.ResponseTypeMap.TryGetCommandResponseType<TCommand>(out Type commandResponseType))
90+
{
91+
throw new InvalidOperationException($"Type {typeof(TCommand)} does not correspond to a known command response type.");
92+
}
93+
94+
return (ICommandResponse<TCommand>)responseJson.Deserialize(commandResponseType, jsonResponseSerializerOptions);
95+
}
96+
97+
internal override TCommandResponse Deserialize<TCommandResponse>(JsonElement responseJson)
98+
{
99+
return responseJson.Deserialize<TCommandResponse>(jsonResponseSerializerOptions);
100+
}
67101
}
68102
}
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
using System.Text.Json.Serialization;
2+
3+
namespace OpenQA.Selenium.DevTools.V85;
4+
5+
[JsonSerializable(typeof(ICommand))]
6+
internal sealed partial class V85RequestSerializationContext : JsonSerializerContext;
7+
8+
[JsonSerializable(typeof(ICommand))]
9+
internal sealed partial class V85ResponseSerializationContext : JsonSerializerContext;

0 commit comments

Comments
 (0)