diff --git a/dotnet/src/webdriver/Response.cs b/dotnet/src/webdriver/Response.cs index 133d82af1619d..8f643e7082809 100644 --- a/dotnet/src/webdriver/Response.cs +++ b/dotnet/src/webdriver/Response.cs @@ -19,10 +19,10 @@ using OpenQA.Selenium.Internal; using System; -using System.Collections.Generic; using System.Diagnostics.CodeAnalysis; using System.Globalization; using System.Text.Json; +using System.Text.Json.Nodes; using System.Text.Json.Serialization; #nullable enable @@ -30,16 +30,10 @@ namespace OpenQA.Selenium { /// - /// Handles reponses from the browser + /// Handles responses from the browser /// public class Response { - private static readonly JsonSerializerOptions s_jsonSerializerOptions = new() - { - TypeInfoResolver = ResponseJsonSerializerContext.Default, - Converters = { new ResponseValueJsonConverter() } // we still need it to make `Object` as `Dictionary` - }; - /// /// Initializes a new instance of the class /// @@ -62,18 +56,18 @@ public Response(string? sessionId, object? value, WebDriverResult status) /// If is not a valid JSON object. public static Response FromJson(string value) { - Dictionary rawResponse = JsonSerializer.Deserialize>(value, s_jsonSerializerOptions) - ?? throw new WebDriverException("JSON success response returned \"null\" value"); + JsonObject rawResponse = JsonNode.Parse(value) as JsonObject + ?? throw new WebDriverException($"JSON success response did not return a dictionary{Environment.NewLine}{value}"); - object? contents; + JsonNode? contents; string? sessionId = null; - if (rawResponse.TryGetValue("sessionId", out object? s) && s is not null) + if (rawResponse.TryGetPropertyValue("sessionId", out JsonNode? s) && s is not null) { sessionId = s.ToString(); } - if (rawResponse.TryGetValue("value", out object? valueObj)) + if (rawResponse.TryGetPropertyValue("value", out JsonNode? valueObj)) { contents = valueObj; } @@ -87,7 +81,7 @@ public static Response FromJson(string value) // Special-case for the new session command, where the "capabilities" // property of the response is the actual value we're interested in. - if (rawResponse.TryGetValue("capabilities", out object? capabilities)) + if (rawResponse.TryGetPropertyValue("capabilities", out JsonNode? capabilities)) { contents = capabilities; } @@ -97,14 +91,14 @@ public static Response FromJson(string value) } } - if (contents is Dictionary valueDictionary) + if (contents is JsonObject valueDictionary) { // Special case code for the new session command. If the response contains // sessionId and capabilities properties, fix up the session ID and value members. - if (valueDictionary.TryGetValue("sessionId", out object? session)) + if (valueDictionary.TryGetPropertyValue("sessionId", out JsonNode? session)) { - sessionId = session.ToString(); - if (valueDictionary.TryGetValue("capabilities", out object? capabilities)) + sessionId = session?.ToString(); + if (valueDictionary.TryGetPropertyValue("capabilities", out JsonNode? capabilities)) { contents = capabilities; } @@ -115,7 +109,9 @@ public static Response FromJson(string value) } } - return new Response(sessionId, contents, WebDriverResult.Success); + var contentsDictionary = JsonSerializer.Deserialize(contents, ResponseJsonSerializerContext.Default.Object); + + return new Response(sessionId, contentsDictionary, WebDriverResult.Success); } /// @@ -143,29 +139,30 @@ public static Response FromJson(string value) /// If the JSON dictionary is not in the expected state, per spec. public static Response FromErrorJson(string value) { - Dictionary deserializedResponse = JsonSerializer.Deserialize>(value, s_jsonSerializerOptions) - ?? throw new WebDriverException("JSON error response returned \"null\" value"); + JsonObject responseObject = JsonNode.Parse(value) as JsonObject + ?? throw new WebDriverException($"JSON error response did not return an object{Environment.NewLine}{value}"); - if (!deserializedResponse.TryGetValue("value", out object? valueObject)) + if (!responseObject.TryGetPropertyValue("value", out JsonNode? valueNode)) { - throw new WebDriverException($"The 'value' property was not found in the response:{Environment.NewLine}{value}"); + throw new WebDriverException($"The 'value' property was not found in the response{Environment.NewLine}{value}"); } - if (valueObject is not Dictionary valueDictionary) + if (valueNode is not JsonObject valueObject) { - throw new WebDriverException($"The 'value' property is not a dictionary of {Environment.NewLine}{value}"); + throw new WebDriverException($"The 'value' property is not a dictionary{Environment.NewLine}{value}"); } - if (!valueDictionary.TryGetValue("error", out object? errorObject)) + if (!valueObject.TryGetPropertyValue("error", out JsonNode? errorObject)) { - throw new WebDriverException($"The 'value > error' property was not found in the response:{Environment.NewLine}{value}"); + throw new WebDriverException($"The 'value > error' property was not found in the response{Environment.NewLine}{value}"); } - if (errorObject is not string errorString) + if (errorObject is not JsonValue errorValue || !errorValue.TryGetValue(out string? errorString)) { throw new WebDriverException($"The 'value > error' property is not a string{Environment.NewLine}{value}"); } + var valueDictionary = JsonSerializer.Deserialize(valueObject, ResponseJsonSerializerContext.Default.Object); WebDriverResult status = WebDriverError.ResultFromError(errorString); return new Response(sessionId: null, valueDictionary, status); @@ -205,6 +202,7 @@ public override string ToString() } } - [JsonSerializable(typeof(Dictionary))] + [JsonSerializable(typeof(object))] + [JsonSourceGenerationOptions(Converters = [typeof(ResponseValueJsonConverter)])] // we still need it to make `Object` as `Dictionary` internal sealed partial class ResponseJsonSerializerContext : JsonSerializerContext; }