Skip to content

Commit dfb3810

Browse files
authored
Merge pull request #160 from graphql-dotnet/pluggable-serializers
Pluggable JSON Serializer
2 parents 1a35989 + 94c2d91 commit dfb3810

File tree

83 files changed

+1573
-494
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

83 files changed

+1573
-494
lines changed

GraphQL.Client.sln

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,18 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "GraphQL.Client.Abstractions
5858
EndProject
5959
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "GraphQL.Client", "src\GraphQL.Client\GraphQL.Client.csproj", "{ED3541C9-D2B2-4D06-A464-38E404A3919A}"
6060
EndProject
61+
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "GraphQL.Client.Abstractions.Websocket", "src\GraphQL.Client.Abstractions.Websocket\GraphQL.Client.Abstractions.Websocket.csproj", "{4D581CE1-523D-46BF-BAA5-F7D79A1B7654}"
62+
EndProject
63+
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "GraphQL.Client.Serializer.Newtonsoft", "src\GraphQL.Client.Serializer.Newtonsoft\GraphQL.Client.Serializer.Newtonsoft.csproj", "{11F28E78-ADE4-4153-B97C-56136EB7BD5B}"
64+
EndProject
65+
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "GraphQL.Client.LocalExecution", "src\GraphQL.Client.LocalExecution\GraphQL.Client.LocalExecution.csproj", "{2BEC821C-E405-43CB-9BC9-A6BB0322F6C2}"
66+
EndProject
67+
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "GraphQL.Client.Serializer.Tests", "tests\GraphQL.Client.Serializer.Tests\GraphQL.Client.Serializer.Tests.csproj", "{CA842D18-FC4A-4281-B1FF-080FA91887B8}"
68+
EndProject
69+
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "GraphQL.Client.Tests.Common", "tests\GraphQL.Client.Tests.Common\GraphQL.Client.Tests.Common.csproj", "{0D307BAD-27AE-4A5D-8764-4AA2620B01E9}"
70+
EndProject
71+
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "GraphQL.Client.Serializer.SystemTextJson", "src\GraphQL.Client.Serializer.SystemTextJson\GraphQL.Client.Serializer.SystemTextJson.csproj", "{7FFFEC00-D751-4FFC-9FD4-E91858F9A1C5}"
72+
EndProject
6173
Global
6274
GlobalSection(SolutionConfigurationPlatforms) = preSolution
6375
Debug|Any CPU = Debug|Any CPU
@@ -96,6 +108,30 @@ Global
96108
{ED3541C9-D2B2-4D06-A464-38E404A3919A}.Debug|Any CPU.Build.0 = Debug|Any CPU
97109
{ED3541C9-D2B2-4D06-A464-38E404A3919A}.Release|Any CPU.ActiveCfg = Release|Any CPU
98110
{ED3541C9-D2B2-4D06-A464-38E404A3919A}.Release|Any CPU.Build.0 = Release|Any CPU
111+
{4D581CE1-523D-46BF-BAA5-F7D79A1B7654}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
112+
{4D581CE1-523D-46BF-BAA5-F7D79A1B7654}.Debug|Any CPU.Build.0 = Debug|Any CPU
113+
{4D581CE1-523D-46BF-BAA5-F7D79A1B7654}.Release|Any CPU.ActiveCfg = Release|Any CPU
114+
{4D581CE1-523D-46BF-BAA5-F7D79A1B7654}.Release|Any CPU.Build.0 = Release|Any CPU
115+
{11F28E78-ADE4-4153-B97C-56136EB7BD5B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
116+
{11F28E78-ADE4-4153-B97C-56136EB7BD5B}.Debug|Any CPU.Build.0 = Debug|Any CPU
117+
{11F28E78-ADE4-4153-B97C-56136EB7BD5B}.Release|Any CPU.ActiveCfg = Release|Any CPU
118+
{11F28E78-ADE4-4153-B97C-56136EB7BD5B}.Release|Any CPU.Build.0 = Release|Any CPU
119+
{2BEC821C-E405-43CB-9BC9-A6BB0322F6C2}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
120+
{2BEC821C-E405-43CB-9BC9-A6BB0322F6C2}.Debug|Any CPU.Build.0 = Debug|Any CPU
121+
{2BEC821C-E405-43CB-9BC9-A6BB0322F6C2}.Release|Any CPU.ActiveCfg = Release|Any CPU
122+
{2BEC821C-E405-43CB-9BC9-A6BB0322F6C2}.Release|Any CPU.Build.0 = Release|Any CPU
123+
{CA842D18-FC4A-4281-B1FF-080FA91887B8}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
124+
{CA842D18-FC4A-4281-B1FF-080FA91887B8}.Debug|Any CPU.Build.0 = Debug|Any CPU
125+
{CA842D18-FC4A-4281-B1FF-080FA91887B8}.Release|Any CPU.ActiveCfg = Release|Any CPU
126+
{CA842D18-FC4A-4281-B1FF-080FA91887B8}.Release|Any CPU.Build.0 = Release|Any CPU
127+
{0D307BAD-27AE-4A5D-8764-4AA2620B01E9}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
128+
{0D307BAD-27AE-4A5D-8764-4AA2620B01E9}.Debug|Any CPU.Build.0 = Debug|Any CPU
129+
{0D307BAD-27AE-4A5D-8764-4AA2620B01E9}.Release|Any CPU.ActiveCfg = Release|Any CPU
130+
{0D307BAD-27AE-4A5D-8764-4AA2620B01E9}.Release|Any CPU.Build.0 = Release|Any CPU
131+
{7FFFEC00-D751-4FFC-9FD4-E91858F9A1C5}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
132+
{7FFFEC00-D751-4FFC-9FD4-E91858F9A1C5}.Debug|Any CPU.Build.0 = Debug|Any CPU
133+
{7FFFEC00-D751-4FFC-9FD4-E91858F9A1C5}.Release|Any CPU.ActiveCfg = Release|Any CPU
134+
{7FFFEC00-D751-4FFC-9FD4-E91858F9A1C5}.Release|Any CPU.Build.0 = Release|Any CPU
99135
EndGlobalSection
100136
GlobalSection(SolutionProperties) = preSolution
101137
HideSolutionNode = FALSE
@@ -109,6 +145,12 @@ Global
109145
{C68C26EB-7659-402A-93D1-E6E248DA5427} = {0B0EDB0F-FF67-4B78-A8DB-B5C23E1FEE8C}
110146
{76E622F6-7CDD-4B1F-AD06-FFABF37C55E5} = {47C98B55-08F1-4428-863E-2C5C876DEEFE}
111147
{ED3541C9-D2B2-4D06-A464-38E404A3919A} = {47C98B55-08F1-4428-863E-2C5C876DEEFE}
148+
{4D581CE1-523D-46BF-BAA5-F7D79A1B7654} = {47C98B55-08F1-4428-863E-2C5C876DEEFE}
149+
{11F28E78-ADE4-4153-B97C-56136EB7BD5B} = {47C98B55-08F1-4428-863E-2C5C876DEEFE}
150+
{2BEC821C-E405-43CB-9BC9-A6BB0322F6C2} = {47C98B55-08F1-4428-863E-2C5C876DEEFE}
151+
{CA842D18-FC4A-4281-B1FF-080FA91887B8} = {0B0EDB0F-FF67-4B78-A8DB-B5C23E1FEE8C}
152+
{0D307BAD-27AE-4A5D-8764-4AA2620B01E9} = {0B0EDB0F-FF67-4B78-A8DB-B5C23E1FEE8C}
153+
{7FFFEC00-D751-4FFC-9FD4-E91858F9A1C5} = {47C98B55-08F1-4428-863E-2C5C876DEEFE}
112154
EndGlobalSection
113155
GlobalSection(ExtensibilityGlobals) = postSolution
114156
SolutionGuid = {387AC1AC-F90C-4EF8-955A-04D495C75AF4}
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
<Project Sdk="Microsoft.NET.Sdk">
2+
<Import Project="../src.props" />
3+
4+
<PropertyGroup>
5+
<TargetFramework>netstandard2.0</TargetFramework>
6+
<LangVersion>8.0</LangVersion>
7+
</PropertyGroup>
8+
9+
<ItemGroup>
10+
<ProjectReference Include="..\GraphQL.Client.Abstractions\GraphQL.Client.Abstractions.csproj" />
11+
</ItemGroup>
12+
13+
</Project>

src/GraphQL.Client/Websocket/GraphQLWebSocketMessageType.cs renamed to src/GraphQL.Client.Abstractions.Websocket/GraphQLWebSocketMessageType.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
namespace GraphQL.Client.Http.Websocket {
1+
namespace GraphQL.Client.Abstractions.Websocket {
22
public static class GraphQLWebSocketMessageType {
33

44
/// <summary>

src/GraphQL.Client/Websocket/GraphQLWebSocketRequest.cs renamed to src/GraphQL.Client.Abstractions.Websocket/GraphQLWebSocketRequest.cs

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,28 +1,35 @@
11
using System;
22
using System.Collections.Generic;
3+
using System.Runtime.Serialization;
34
using System.Threading.Tasks;
45

5-
namespace GraphQL.Client.Http.Websocket {
6+
namespace GraphQL.Client.Abstractions.Websocket {
67

78
/// <summary>
89
/// A Subscription Request
910
/// </summary>
1011
public class GraphQLWebSocketRequest : IEquatable<GraphQLWebSocketRequest> {
12+
public const string IdKey = "id";
13+
public const string TypeKey = "type";
14+
public const string PayloadKey = "payload";
1115

1216
/// <summary>
1317
/// The Identifier of the Response
1418
/// </summary>
15-
public string Id { get; set; }
19+
[DataMember(Name = IdKey)]
20+
public virtual string Id { get; set; }
1621

1722
/// <summary>
1823
/// The Type of the Request
1924
/// </summary>
20-
public string Type { get; set; }
25+
[DataMember(Name = TypeKey)]
26+
public virtual string Type { get; set; }
2127

2228
/// <summary>
2329
/// The payload of the websocket request
2430
/// </summary>
25-
public GraphQLRequest Payload { get; set; }
31+
[DataMember(Name = PayloadKey)]
32+
public virtual GraphQLRequest Payload { get; set; }
2633

2734
private TaskCompletionSource<bool> _tcs = new TaskCompletionSource<bool>();
2835

src/GraphQL.Client/Websocket/GraphQLWebSocketResponse.cs renamed to src/GraphQL.Client.Abstractions.Websocket/GraphQLWebSocketResponse.cs

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
using System;
22
using System.Collections.Generic;
33

4-
namespace GraphQL.Client.Http.Websocket {
4+
namespace GraphQL.Client.Abstractions.Websocket {
55

66
/// <summary>
77
/// A Subscription Response
@@ -60,10 +60,10 @@ public override int GetHashCode() {
6060

6161
}
6262

63-
public class GraphQLWebSocketResponse<TResponse> : GraphQLWebSocketResponse, IEquatable<GraphQLWebSocketResponse<TResponse>> {
64-
public GraphQLHttpResponse<TResponse> Payload { get; set; }
63+
public class GraphQLWebSocketResponse<TPayload> : GraphQLWebSocketResponse, IEquatable<GraphQLWebSocketResponse<TPayload>> {
64+
public TPayload Payload { get; set; }
6565

66-
public bool Equals(GraphQLWebSocketResponse<TResponse>? other) {
66+
public bool Equals(GraphQLWebSocketResponse<TPayload>? other) {
6767
if (ReferenceEquals(null, other)) return false;
6868
if (ReferenceEquals(this, other)) return true;
6969
return base.Equals(other) && Payload.Equals(other.Payload);
@@ -73,7 +73,7 @@ public override bool Equals(object? obj) {
7373
if (ReferenceEquals(null, obj)) return false;
7474
if (ReferenceEquals(this, obj)) return true;
7575
if (obj.GetType() != this.GetType()) return false;
76-
return Equals((GraphQLWebSocketResponse<TResponse>)obj);
76+
return Equals((GraphQLWebSocketResponse<TPayload>)obj);
7777
}
7878

7979
public override int GetHashCode() {
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
using System.IO;
2+
using System.Threading.Tasks;
3+
4+
namespace GraphQL.Client.Abstractions.Websocket
5+
{
6+
/// <summary>
7+
/// The json serializer interface for the graphql-dotnet http client.
8+
/// Implementations should provide a parameterless constructor for convenient usage
9+
/// </summary>
10+
public interface IGraphQLWebsocketJsonSerializer: IGraphQLJsonSerializer {
11+
byte[] SerializeToBytes(GraphQLWebSocketRequest request);
12+
13+
Task<WebsocketResponseWrapper> DeserializeToWebsocketResponseWrapperAsync(Stream stream);
14+
GraphQLWebSocketResponse<GraphQLResponse<TResponse>> DeserializeToWebsocketResponse<TResponse>(byte[] bytes);
15+
16+
}
17+
}

src/GraphQL.Client/Websocket/WebsocketResponseWrapper.cs renamed to src/GraphQL.Client.Abstractions.Websocket/WebsocketResponseWrapper.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
using System.Runtime.Serialization;
22

3-
namespace GraphQL.Client.Http.Websocket {
3+
namespace GraphQL.Client.Abstractions.Websocket {
44
public class WebsocketResponseWrapper : GraphQLWebSocketResponse {
55

66
[IgnoreDataMember]

src/GraphQL.Client.Abstractions/GraphQL.Client.Abstractions.csproj

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@
1313
</ItemGroup>
1414

1515
<ItemGroup>
16-
<PackageReference Include="System.Reactive" Version="4.1.2" />
16+
<PackageReference Include="System.Reactive" Version="4.3.2" />
1717
</ItemGroup>
1818

1919
</Project>
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
using System;
2+
using System.Diagnostics;
3+
using System.Linq;
4+
5+
namespace GraphQL.Client.Abstractions {
6+
public static class GraphQLJsonSerializerExtensions {
7+
public static TSerializerInterface EnsureAssigned<TSerializerInterface>(this TSerializerInterface jsonSerializer) where TSerializerInterface: IGraphQLJsonSerializer {
8+
// if no serializer was assigned
9+
if (jsonSerializer == null) {
10+
// try to find one in the assembly and assign that
11+
var type = typeof(TSerializerInterface);
12+
var serializerType = AppDomain.CurrentDomain
13+
.GetAssemblies()
14+
.SelectMany(s => s.GetTypes())
15+
.FirstOrDefault(p => type.IsAssignableFrom(p) && !p.IsInterface && !p.IsAbstract);
16+
if (serializerType == null)
17+
throw new InvalidOperationException($"no implementation of \"{type}\" found");
18+
19+
jsonSerializer = (TSerializerInterface)Activator.CreateInstance(serializerType);
20+
}
21+
22+
return jsonSerializer;
23+
}
24+
25+
public static TOptions New<TOptions>(this Action<TOptions> configure) =>
26+
configure.AndReturn(Activator.CreateInstance<TOptions>());
27+
28+
public static TOptions AndReturn<TOptions>(this Action<TOptions> configure, TOptions options) {
29+
configure(options);
30+
return options;
31+
}
32+
}
33+
}

src/GraphQL.Client.Abstractions/IGraphQLClient.cs

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -31,11 +31,6 @@ public interface IGraphQLClient : IDisposable {
3131
/// <param name="exceptionHandler">an external handler for all <see cref="Exception"/>s occuring within the sequence</param>
3232
/// <returns>an observable stream for the specified subscription</returns>
3333
IObservable<GraphQLResponse<TResponse>> CreateSubscriptionStream<TResponse>(GraphQLRequest request, Action<Exception> exceptionHandler);
34-
35-
/// <summary>
36-
/// Publishes all exceptions which occur inside the websocket receive stream (i.e. for logging purposes)
37-
/// </summary>
38-
IObservable<Exception> WebSocketReceiveErrors { get; }
3934
}
4035

4136
}

0 commit comments

Comments
 (0)