Skip to content

Commit 51f313d

Browse files
authored
Merge branch 'master' into code-cleanup
2 parents cc131e2 + aadf594 commit 51f313d

File tree

8 files changed

+98
-17
lines changed

8 files changed

+98
-17
lines changed

GraphQL.Client.sln

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -33,10 +33,8 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "GraphQL.Server.Test", "test
3333
EndProject
3434
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "workflows", "workflows", "{05CAF9B2-981E-40C0-AE31-5FA56E351F12}"
3535
ProjectSection(SolutionItems) = preProject
36-
.github\workflows\branches-ubuntu.yml = .github\workflows\branches-ubuntu.yml
37-
.github\workflows\branches-windows.yml = .github\workflows\branches-windows.yml
38-
.github\workflows\main-ubuntu.yml = .github\workflows\main-ubuntu.yml
39-
.github\workflows\main-windows.yml = .github\workflows\main-windows.yml
36+
.github\workflows\branches.yml = .github\workflows\branches.yml
37+
.github\workflows\master.yml = .github\workflows\master.yml
4038
EndProjectSection
4139
EndProject
4240
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "GraphQL.Primitives", "src\GraphQL.Primitives\GraphQL.Primitives.csproj", "{87FC440E-6A4D-47D8-9EB2-416FC31CC4A6}"

src/GraphQL.Client.Serializer.Newtonsoft/MapConverter.cs

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
using System;
22
using System.Collections.Generic;
3+
using System.Linq;
34
using Newtonsoft.Json;
45
using Newtonsoft.Json.Linq;
56

@@ -22,11 +23,11 @@ public override Map ReadJson(JsonReader reader, Type objectType, Map existingVal
2223
throw new ArgumentException("This converter can only parse when the root element is a JSON Object.");
2324
}
2425

25-
private object ReadToken(JToken? token) =>
26+
private object? ReadToken(JToken? token) =>
2627
token switch
2728
{
2829
JObject jObject => ReadDictionary(jObject, new Dictionary<string, object>()),
29-
JArray jArray => ReadArray(jArray),
30+
JArray jArray => ReadArray(jArray).ToList(),
3031
JValue jValue => jValue.Value,
3132
JConstructor _ => throw new ArgumentOutOfRangeException(nameof(token.Type),
3233
"cannot deserialize a JSON constructor"),
@@ -48,7 +49,7 @@ private Dictionary<string, object> ReadDictionary(JToken element, Dictionary<str
4849
return to;
4950
}
5051

51-
private IEnumerable<object> ReadArray(JArray element)
52+
private IEnumerable<object?> ReadArray(JArray element)
5253
{
5354
foreach (var item in element)
5455
{

src/GraphQL.Client.Serializer.SystemTextJson/MapConverter.cs

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -41,15 +41,15 @@ private TDictionary ReadDictionary<TDictionary>(JsonElement element) where TDict
4141
return result;
4242
}
4343

44-
private IEnumerable<object> ReadArray(JsonElement value)
44+
private IEnumerable<object?> ReadArray(JsonElement value)
4545
{
4646
foreach (var item in value.EnumerateArray())
4747
{
4848
yield return ReadValue(item);
4949
}
5050
}
5151

52-
private object ReadValue(JsonElement value)
52+
private object? ReadValue(JsonElement value)
5353
=> value.ValueKind switch
5454
{
5555
JsonValueKind.Array => ReadArray(value).ToList(),
@@ -65,15 +65,15 @@ private object ReadValue(JsonElement value)
6565

6666
private object ReadNumber(JsonElement value)
6767
{
68-
if (value.TryGetInt32(out var i))
68+
if (value.TryGetInt32(out int i))
6969
return i;
70-
else if (value.TryGetInt64(out var l))
70+
else if (value.TryGetInt64(out long l))
7171
return l;
7272
else if (BigInteger.TryParse(value.GetRawText(), out var bi))
7373
return bi;
74-
else if (value.TryGetDouble(out var d))
74+
else if (value.TryGetDouble(out double d))
7575
return d;
76-
else if (value.TryGetDecimal(out var dd))
76+
else if (value.TryGetDecimal(out decimal dd))
7777
return dd;
7878

7979
throw new NotImplementedException($"Unexpected Number value. Raw text was: {value.GetRawText()}");

src/GraphQL.Client/GraphQLHttpClientOptions.cs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
using System;
22
using System.Net.Http;
33
using System.Net.Http.Headers;
4+
using System.Net.WebSockets;
45
using System.Threading.Tasks;
56

67
namespace GraphQL.Client.Http
@@ -50,5 +51,10 @@ public class GraphQLHttpClientOptions
5051
/// This callback is called after successfully establishing a websocket connection but before any regular request is made.
5152
/// </summary>
5253
public Func<GraphQLHttpClient, Task> OnWebsocketConnected { get; set; } = client => Task.CompletedTask;
54+
55+
/// <summary>
56+
/// Configure additional websocket options (i.e. headers). This will not be invoked on Windows 7 when targeting .NET Framework 4.x.
57+
/// </summary>
58+
public Action<ClientWebSocketOptions> ConfigureWebsocketOptions { get; set; } = options => { };
5359
}
5460
}

src/GraphQL.Client/Websocket/GraphQLHttpWebSocket.cs

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -396,12 +396,13 @@ public Task InitializeWebSocket()
396396
nativeWebSocket.Options.AddSubProtocol("graphql-ws");
397397
nativeWebSocket.Options.ClientCertificates = ((HttpClientHandler)Options.HttpMessageHandler).ClientCertificates;
398398
nativeWebSocket.Options.UseDefaultCredentials = ((HttpClientHandler)Options.HttpMessageHandler).UseDefaultCredentials;
399-
break;
399+
Options.ConfigureWebsocketOptions(nativeWebSocket.Options);
400+
break;
400401
case System.Net.WebSockets.Managed.ClientWebSocket managedWebSocket:
401402
managedWebSocket.Options.AddSubProtocol("graphql-ws");
402403
managedWebSocket.Options.ClientCertificates = ((HttpClientHandler)Options.HttpMessageHandler).ClientCertificates;
403404
managedWebSocket.Options.UseDefaultCredentials = ((HttpClientHandler)Options.HttpMessageHandler).UseDefaultCredentials;
404-
break;
405+
break;
405406
default:
406407
throw new NotSupportedException($"unknown websocket type {_clientWebSocket.GetType().Name}");
407408
}
@@ -410,6 +411,7 @@ public Task InitializeWebSocket()
410411
_clientWebSocket.Options.AddSubProtocol("graphql-ws");
411412
_clientWebSocket.Options.ClientCertificates = ((HttpClientHandler)Options.HttpMessageHandler).ClientCertificates;
412413
_clientWebSocket.Options.UseDefaultCredentials = ((HttpClientHandler)Options.HttpMessageHandler).UseDefaultCredentials;
414+
Options.ConfigureWebsocketOptions(_clientWebSocket.Options);
413415
#endif
414416
return _initializeWebSocketTask = ConnectAsync(_internalCancellationToken);
415417
}
@@ -607,7 +609,7 @@ public void Complete()
607609
/// Task to await the completion (a.k.a. disposal) of this websocket.
608610
/// </summary>
609611
/// Async disposal as recommended by Stephen Cleary (https://blog.stephencleary.com/2013/03/async-oop-6-disposal.html)
610-
public Task Completion { get; private set; }
612+
public Task? Completion { get; private set; }
611613

612614
private readonly object _completedLocker = new object();
613615
private async Task CompleteAsync()

src/GraphQL.Primitives/GraphQLResponse.cs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,10 +5,11 @@
55

66
namespace GraphQL
77
{
8-
public class GraphQLResponse<T> : IEquatable<GraphQLResponse<T>?>
8+
public class GraphQLResponse<T> : IGraphQLResponse, IEquatable<GraphQLResponse<T>?>
99
{
1010
[DataMember(Name = "data")]
1111
public T Data { get; set; }
12+
object IGraphQLResponse.Data => Data;
1213

1314
[DataMember(Name = "errors")]
1415
public GraphQLError[]? Errors { get; set; }
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
namespace GraphQL
2+
{
3+
public interface IGraphQLResponse
4+
{
5+
object Data { get; }
6+
7+
GraphQLError[]? Errors { get; set; }
8+
9+
Map? Extensions { get; set; }
10+
}
11+
}
Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
using System.Collections.Generic;
2+
using FluentAssertions;
3+
using FluentAssertions.Execution;
4+
using GraphQL.Client.Serializer.Newtonsoft;
5+
using GraphQL.Client.Serializer.SystemTextJson;
6+
using Newtonsoft.Json;
7+
using Xunit;
8+
9+
namespace GraphQL.Client.Serializer.Tests
10+
{
11+
public class ConsistencyTests
12+
{
13+
[Fact]
14+
public void MapConvertersShouldBehaveConsistent()
15+
{
16+
const string json = @"{
17+
""array"": [
18+
""some stuff"",
19+
""something else""
20+
],
21+
""string"": ""this is a string"",
22+
""boolean"": true,
23+
""number"": 1234.567,
24+
""nested object"": {
25+
""prop1"": false
26+
},
27+
""arrayOfObjects"": [
28+
{""number"": 1234.567},
29+
{""number"": 567.8}
30+
]
31+
}";
32+
33+
var newtonsoftSerializer = new NewtonsoftJsonSerializer();
34+
var systemTextJsonSerializer = new SystemTextJsonSerializer();
35+
36+
var newtonsoftMap = JsonConvert.DeserializeObject<Map>(json, newtonsoftSerializer.JsonSerializerSettings);
37+
var systemTextJsonMap = System.Text.Json.JsonSerializer.Deserialize<Map>(json, systemTextJsonSerializer.Options);
38+
39+
40+
using(new AssertionScope())
41+
{
42+
CompareMaps(newtonsoftMap, systemTextJsonMap);
43+
}
44+
45+
newtonsoftMap.Should().BeEquivalentTo(systemTextJsonMap, options => options
46+
.RespectingRuntimeTypes());
47+
}
48+
49+
private void CompareMaps(Dictionary<string, object> first, Dictionary<string, object> second)
50+
{
51+
foreach (var keyValuePair in first)
52+
{
53+
second.Should().ContainKey(keyValuePair.Key);
54+
second[keyValuePair.Key].Should().BeOfType(keyValuePair.Value.GetType());
55+
if(keyValuePair.Value is Dictionary<string, object> map)
56+
CompareMaps(map, (Dictionary<string, object>)second[keyValuePair.Key]);
57+
else
58+
keyValuePair.Value.Should().BeEquivalentTo(second[keyValuePair.Key]);
59+
}
60+
}
61+
}
62+
}

0 commit comments

Comments
 (0)