Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[dotnet] Modernize Response type #14839

Merged
merged 11 commits into from
Dec 8, 2024
68 changes: 25 additions & 43 deletions dotnet/src/webdriver/Response.cs
Original file line number Diff line number Diff line change
Expand Up @@ -31,16 +31,12 @@ namespace OpenQA.Selenium
/// </summary>
public class Response
{
private readonly static JsonSerializerOptions s_jsonSerializerOptions = new()
private static readonly JsonSerializerOptions s_jsonSerializerOptions = new()
{
TypeInfoResolver = ResponseJsonSerializerContext.Default,
Converters = { new ResponseValueJsonConverter() } // we still need it to make `Object` as `Dictionary`
};

private object responseValue;
private string responseSessionId;
private WebDriverResult responseStatus;

/// <summary>
/// Initializes a new instance of the <see cref="Response"/> class
/// </summary>
Expand All @@ -56,7 +52,7 @@ public Response(SessionId sessionId)
{
if (sessionId != null)
{
this.responseSessionId = sessionId.ToString();
this.SessionId = sessionId.ToString();
}
}

Expand All @@ -66,49 +62,48 @@ private Response(Dictionary<string, object> rawResponse)
{
if (rawResponse["sessionId"] != null)
{
this.responseSessionId = rawResponse["sessionId"].ToString();
this.SessionId = rawResponse["sessionId"].ToString();
}
}

if (rawResponse.ContainsKey("value"))
if (rawResponse.TryGetValue("value", out object value))
{
this.responseValue = rawResponse["value"];
this.Value = value;
}

// If the returned object does *not* have a "value" property
// the response value should be the entirety of the response.
// TODO: Remove this if statement altogether; there should
// never be a spec-compliant response that does not contain a
// value property.
if (!rawResponse.ContainsKey("value") && this.responseValue == null)
if (!rawResponse.ContainsKey("value") && this.Value == null)
{
// Special-case for the new session command, where the "capabilities"
// property of the response is the actual value we're interested in.
if (rawResponse.ContainsKey("capabilities"))
{
this.responseValue = rawResponse["capabilities"];
this.Value = rawResponse["capabilities"];
}
else
{
this.responseValue = rawResponse;
this.Value = rawResponse;
}
}

Dictionary<string, object> valueDictionary = this.responseValue as Dictionary<string, object>;
if (valueDictionary != null)
if (this.Value is Dictionary<string, object> 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.ContainsKey("sessionId"))
{
this.responseSessionId = valueDictionary["sessionId"].ToString();
if (valueDictionary.ContainsKey("capabilities"))
this.SessionId = valueDictionary["sessionId"].ToString();
if (valueDictionary.TryGetValue("capabilities", out object capabilities))
{
this.responseValue = valueDictionary["capabilities"];
this.Value = capabilities;
}
else
{
this.responseValue = valueDictionary["value"];
this.Value = valueDictionary["value"];
}
}
}
Expand All @@ -117,29 +112,17 @@ private Response(Dictionary<string, object> rawResponse)
/// <summary>
/// Gets or sets the value from JSON.
/// </summary>
public object Value
{
get { return this.responseValue; }
set { this.responseValue = value; }
}
public object Value { get; set; }

/// <summary>
/// Gets or sets the session ID.
/// </summary>
public string SessionId
{
get { return this.responseSessionId; }
set { this.responseSessionId = value; }
}
public string SessionId { get; set; }

/// <summary>
/// Gets or sets the status value of the response.
/// </summary>
public WebDriverResult Status
{
get { return this.responseStatus; }
set { this.responseStatus = value; }
}
public WebDriverResult Status { get; set; }

/// <summary>
/// Returns a new <see cref="Response"/> from a JSON-encoded string.
Expand All @@ -148,9 +131,10 @@ public WebDriverResult Status
/// <returns>A <see cref="Response"/> object described by the JSON string.</returns>
public static Response FromJson(string value)
{
Dictionary<string, object> deserializedResponse = JsonSerializer.Deserialize<Dictionary<string, object>>(value, s_jsonSerializerOptions);
Response response = new Response(deserializedResponse);
return response;
Dictionary<string, object> deserializedResponse = JsonSerializer.Deserialize<Dictionary<string, object>>(value, s_jsonSerializerOptions)
?? throw new WebDriverException("JSON success response returned \"null\" value");

return new Response(deserializedResponse);
}

/// <summary>
Expand All @@ -160,7 +144,8 @@ public static Response FromJson(string value)
/// <returns>A <see cref="Response"/> object described by the JSON string.</returns>
public static Response FromErrorJson(string value)
{
var deserializedResponse = JsonSerializer.Deserialize<Dictionary<string, object>>(value, s_jsonSerializerOptions);
var deserializedResponse = JsonSerializer.Deserialize<Dictionary<string, object>>(value, s_jsonSerializerOptions)
?? throw new WebDriverException("JSON error response returned \"null\" value");

var response = new Response();

Expand All @@ -181,14 +166,14 @@ public static Response FromErrorJson(string value)
throw new WebDriverException($"The 'value > error' property was not found in the response:{Environment.NewLine}{value}");
}

if (errorObject is not string)
if (errorObject is not string errorString)
{
throw new WebDriverException($"The 'value > error' property is not a string{Environment.NewLine}{value}");
}

response.Value = deserializedResponse["value"];

response.Status = WebDriverError.ResultFromError(errorObject.ToString());
response.Status = WebDriverError.ResultFromError(errorString);

return response;
}
Expand All @@ -213,8 +198,5 @@ public override string ToString()
}

[JsonSerializable(typeof(Dictionary<string, object>))]
internal partial class ResponseJsonSerializerContext : JsonSerializerContext
{

}
internal sealed partial class ResponseJsonSerializerContext : JsonSerializerContext;
}
Loading