Skip to content

Commit dad7edd

Browse files
committed
Added System.Text.Json serializer project (doesn't work yet). Known issues:
1. Lacks support for DataContract/DataMember attributes: dotnet/runtime#29975 dotnet/runtime#30009 2. Deserializes the primitive values as JsonElement instances.
1 parent 40a9621 commit dad7edd

10 files changed

+244
-1
lines changed
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
using System.Text.Json.Serialization;
2+
using JsonServices.Messages;
3+
4+
namespace JsonServices.Serialization.SystemTextJson.Internal
5+
{
6+
internal class GenericMessage
7+
{
8+
[JsonPropertyName("jsonrpc")]
9+
public string Version { get; set; }
10+
11+
[JsonPropertyName("method")]
12+
public string Name { get; set; }
13+
14+
[JsonPropertyName("error")]
15+
public Error Error { get; set; }
16+
17+
[JsonPropertyName("id")]
18+
public string Id { get; set; }
19+
20+
public bool IsValid => Version == "2.0" &&
21+
(!string.IsNullOrWhiteSpace(Name) || !string.IsNullOrWhiteSpace(Id));
22+
}
23+
}
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
namespace JsonServices.Serialization.SystemTextJson.Internal
2+
{
3+
internal interface IRequestMessage
4+
{
5+
object Parameters { get; }
6+
}
7+
}
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
namespace JsonServices.Serialization.SystemTextJson.Internal
2+
{
3+
internal interface IResponseMessage
4+
{
5+
object Result { get; }
6+
}
7+
}
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
using System.Runtime.Serialization;
2+
using System.Text.Json.Serialization;
3+
4+
namespace JsonServices.Serialization.SystemTextJson.Internal
5+
{
6+
internal class RequestMsg<T> : IRequestMessage
7+
{
8+
[JsonPropertyName("params")]
9+
public T Parameters { get; set; }
10+
object IRequestMessage.Parameters => Parameters;
11+
}
12+
}
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
using System.Text.Json.Serialization;
2+
3+
namespace JsonServices.Serialization.SystemTextJson.Internal
4+
{
5+
internal class ResponseMsg<T> : IResponseMessage
6+
{
7+
[JsonPropertyName("result")]
8+
public T Result { get; set; }
9+
object IResponseMessage.Result => Result;
10+
}
11+
}
Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
<Project Sdk="Microsoft.NET.Sdk">
2+
3+
<PropertyGroup>
4+
<Title>JsonServices.Serialization.SystemTextJson</Title>
5+
<Version>0.0.0.1</Version>
6+
<Authors>yallie</Authors>
7+
<Copyright>Copyright Alexey Yakovlev 2020. All Rights Reserved.</Copyright>
8+
<Description>C# Message-Based JSON-RPC Client over WebSockets</Description>
9+
<PackageLicenseUrl>https://github.com/yallie/JsonService/blob/master/LICENSE</PackageLicenseUrl>
10+
<PackageProjectUrl>https://github.com/yallie/JsonService</PackageProjectUrl>
11+
<RepositoryUrl>https://github.com/yallie/JsonService</RepositoryUrl>
12+
<PackageTags>websockets json rpc events</PackageTags>
13+
<TargetFrameworks>net461;netstandard2.0</TargetFrameworks>
14+
</PropertyGroup>
15+
16+
<PropertyGroup>
17+
<CodeAnalysisRuleSet>..\JsonServices.ruleset</CodeAnalysisRuleSet>
18+
<RootNamespace>JsonServices.Serialization.SystemTextJson</RootNamespace>
19+
<AssemblyName>JsonServices.Serialization.SystemTextJson</AssemblyName>
20+
</PropertyGroup>
21+
22+
<PropertyGroup Condition=" '$(Configuration)' == 'Debug' ">
23+
<DebugType>Full</DebugType>
24+
<DebugSymbols>True</DebugSymbols>
25+
<BaseOutputPath>..\..\bin</BaseOutputPath>
26+
</PropertyGroup>
27+
28+
<ItemGroup>
29+
<PackageReference Include="System.Text.Json" Version="4.7.2" />
30+
</ItemGroup>
31+
32+
<ItemGroup>
33+
<ProjectReference Include="..\JsonServices.Core\JsonServices.Core.csproj" />
34+
</ItemGroup>
35+
36+
<ItemGroup Condition="'$(Configuration)|$(Platform)'=='Debug|AnyCPU'">
37+
<PackageReference Include="StyleCop.Analyzers" Version="1.1.1-beta.61">
38+
<PrivateAssets>all</PrivateAssets>
39+
<IncludeAssets>runtime; build; native; contentfiles; analyzers</IncludeAssets>
40+
</PackageReference>
41+
</ItemGroup>
42+
43+
</Project>
Lines changed: 121 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,121 @@
1+
using System;
2+
using System.Text.Json;
3+
using JsonServices.Exceptions;
4+
using JsonServices.Messages;
5+
using JsonServices.Serialization.SystemTextJson.Internal;
6+
using JsonServices.Services;
7+
8+
namespace JsonServices.Serialization.SystemTextJson
9+
{
10+
public class Serializer : ISerializer
11+
{
12+
public string Serialize(IMessage message) => JsonSerializer.Serialize(message);
13+
14+
public IMessage Deserialize(string data, IMessageTypeProvider typeProvider, IMessageNameProvider nameProvider)
15+
{
16+
var preview = default(GenericMessage);
17+
try
18+
{
19+
preview = JsonSerializer.Deserialize<GenericMessage>(data);
20+
}
21+
catch
22+
{
23+
// invalid message format
24+
}
25+
26+
if (preview == null || !preview.IsValid)
27+
{
28+
throw new InvalidRequestException(data)
29+
{
30+
MessageId = preview?.Id,
31+
};
32+
}
33+
34+
// detect message name
35+
var name = preview.Name;
36+
var isRequest = name != null;
37+
if (name == null)
38+
{
39+
// server cannot handle a response message
40+
if (nameProvider == null)
41+
{
42+
throw new InvalidRequestException(data)
43+
{
44+
MessageId = preview.Id,
45+
};
46+
}
47+
48+
// invalid request id
49+
name = nameProvider.TryGetMessageName(preview.Id);
50+
if (name == null)
51+
{
52+
throw new InvalidRequestException(name)
53+
{
54+
MessageId = preview.Id,
55+
};
56+
}
57+
}
58+
59+
try
60+
{
61+
// deserialize request or response message
62+
if (isRequest)
63+
{
64+
return DeserializeRequest(data, name, preview.Id, typeProvider);
65+
}
66+
67+
return DeserializeResponse(data, name, preview.Id, preview.Error, typeProvider);
68+
}
69+
catch (JsonServicesException ex)
70+
{
71+
// make sure MessageId is reported
72+
if (ex.MessageId == null)
73+
{
74+
ex.MessageId = preview.Id;
75+
}
76+
77+
throw;
78+
}
79+
catch (Exception ex)
80+
{
81+
throw new InvalidRequestException(data, ex)
82+
{
83+
MessageId = preview.Id,
84+
};
85+
}
86+
}
87+
88+
private RequestMessage DeserializeRequest(string data, string name, string id, IMessageTypeProvider typeProvider)
89+
{
90+
// get the message request type
91+
var type = typeProvider.GetRequestType(name);
92+
var msgType = typeof(RequestMsg<>).MakeGenericType(new[] { type });
93+
94+
// deserialize the strong-typed message
95+
var reqMsg = (IRequestMessage)JsonSerializer.Deserialize(data, msgType);
96+
return new RequestMessage
97+
{
98+
Name = name,
99+
Parameters = reqMsg.Parameters,
100+
Id = id,
101+
};
102+
}
103+
104+
public ResponseMessage DeserializeResponse(string data, string name, string id, Error error, IMessageTypeProvider typeProvider)
105+
{
106+
// pre-deserialize to get the bulk of the message
107+
var type = typeProvider.GetResponseType(name);
108+
109+
// handle void messages
110+
if (type == typeof(void))
111+
{
112+
return ResponseMessage.Create(null, error, id);
113+
}
114+
115+
// deserialize the strong-typed message
116+
var msgType = typeof(ResponseMsg<>).MakeGenericType(new[] { type });
117+
var respMsg = (IResponseMessage)JsonSerializer.Deserialize(data, msgType);
118+
return ResponseMessage.Create(respMsg.Result, error, id);
119+
}
120+
}
121+
}

src/JsonServices.Serialization.Tests/JsonServices.Serialization.Tests.csproj

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010
<PackageProjectUrl>https://github.com/yallie/JsonService</PackageProjectUrl>
1111
<RepositoryUrl>https://github.com/yallie/JsonService</RepositoryUrl>
1212
<PackageTags>websockets json rpc events</PackageTags>
13-
<TargetFrameworks>net46;netcoreapp2.0</TargetFrameworks>
13+
<TargetFrameworks>net461;netcoreapp2.0</TargetFrameworks>
1414
<RootNamespace>JsonServices.Serialization.Tests</RootNamespace>
1515
<AssemblyName>JsonServices.Serialization.Tests</AssemblyName>
1616
</PropertyGroup>
@@ -32,6 +32,7 @@
3232
<ProjectReference Include="..\JsonServices.Core\JsonServices.Core.csproj" />
3333
<ProjectReference Include="..\JsonServices.Serialization.Newtonsoft\JsonServices.Serialization.Newtonsoft.csproj" />
3434
<ProjectReference Include="..\JsonServices.Serialization.ServiceStack\JsonServices.Serialization.ServiceStack.csproj" />
35+
<ProjectReference Include="..\JsonServices.Serialization.SystemTextJson\JsonServices.Serialization.SystemTextJson.csproj" />
3536
</ItemGroup>
3637

3738
</Project>
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
using JsonServices.Serialization;
2+
using JsonServices.Serialization.SystemTextJson;
3+
using NUnit.Framework;
4+
5+
namespace JsonServices.Tests.Serialization
6+
{
7+
[TestFixture, Ignore("Doesn't work yet")]
8+
public class SerializerTestsSystemTextJson : SerializerTestsBase
9+
{
10+
protected override ISerializer Serializer { get; } = new Serializer();
11+
}
12+
}

src/JsonServices.sln

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,8 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "JsonServices.Auth.SecureRem
3535
EndProject
3636
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "JsonServices.Sample.CoreServer", "..\sample\sample-core-server\JsonServices.Sample.CoreServer.csproj", "{CA33030D-A387-49CD-9329-042F7B464067}"
3737
EndProject
38+
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "JsonServices.Serialization.SystemTextJson", "JsonServices.Serialization.SystemTextJson\JsonServices.Serialization.SystemTextJson.csproj", "{EE4F39FE-8EFB-4A98-9EFE-953007F4CB74}"
39+
EndProject
3840
Global
3941
GlobalSection(SolutionConfigurationPlatforms) = preSolution
4042
Debug|Any CPU = Debug|Any CPU
@@ -105,6 +107,10 @@ Global
105107
{CA33030D-A387-49CD-9329-042F7B464067}.Debug|Any CPU.Build.0 = Debug|Any CPU
106108
{CA33030D-A387-49CD-9329-042F7B464067}.Release|Any CPU.ActiveCfg = Release|Any CPU
107109
{CA33030D-A387-49CD-9329-042F7B464067}.Release|Any CPU.Build.0 = Release|Any CPU
110+
{EE4F39FE-8EFB-4A98-9EFE-953007F4CB74}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
111+
{EE4F39FE-8EFB-4A98-9EFE-953007F4CB74}.Debug|Any CPU.Build.0 = Debug|Any CPU
112+
{EE4F39FE-8EFB-4A98-9EFE-953007F4CB74}.Release|Any CPU.ActiveCfg = Release|Any CPU
113+
{EE4F39FE-8EFB-4A98-9EFE-953007F4CB74}.Release|Any CPU.Build.0 = Release|Any CPU
108114
EndGlobalSection
109115
GlobalSection(SolutionProperties) = preSolution
110116
HideSolutionNode = FALSE

0 commit comments

Comments
 (0)