Skip to content

Commit c84e37f

Browse files
Make System.Text.Json the default for SignalR and remove Newtonsoft from shared framework (#9476)
1 parent 56c064b commit c84e37f

28 files changed

+240
-158
lines changed

eng/SharedFramework.External.props

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -68,7 +68,6 @@
6868
6969
If these are needed as direct dependencies, it is okay to change them to ExternalAspNetCoreAppReference and move up into sections above.
7070
-->
71-
<_TransitiveExternalAspNetCoreAppReference Include="Newtonsoft.Json" Version="$(NewtonsoftJsonPackageVersion)" />
7271
<_TransitiveExternalAspNetCoreAppReference Include="System.Security.Cryptography.Pkcs" Version="$(SystemSecurityCryptographyPkcsPackageVersion)" />
7372
<_TransitiveExternalAspNetCoreAppReference Include="System.Security.Permissions" Version="$(SystemSecurityPermissionsPackageVersion)" />
7473
</ItemGroup>

eng/SharedFramework.Local.props

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,6 @@
1212
<AspNetCoreAppReferenceAndPackage Include="Microsoft.AspNetCore.Connections.Abstractions" />
1313
<AspNetCoreAppReferenceAndPackage Include="Microsoft.AspNetCore.Http.Connections.Common" />
1414
<AspNetCoreAppReferenceAndPackage Include="Microsoft.AspNetCore.SignalR.Protocols.Json" />
15-
<AspNetCoreAppReferenceAndPackage Include="Microsoft.AspNetCore.SignalR.Protocols.NewtonsoftJson" />
1615
<AspNetCoreAppReferenceAndPackage Include="Microsoft.AspNetCore.SignalR.Common" />
1716
<AspNetCoreAppReferenceAndPackage Include="Microsoft.AspNetCore.Components.Browser" />
1817
<AspNetCoreAppReferenceAndPackage Include="Microsoft.AspNetCore.Components" />

eng/targets/ResolveReferences.targets

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -79,13 +79,11 @@
7979
<_InvalidReferenceToNonSharedFxAssembly Condition="'$(IsAspNetCoreApp)' == 'true'"
8080
Include="@(Reference)"
8181
Exclude="
82-
Newtonsoft.Json;
8382
@(AspNetCoreAppReference);
8483
@(AspNetCoreAppReferenceAndPackage);
8584
@(ExternalAspNetCoreAppReference);
8685
@(_CompilationOnlyReference);
8786
@(Reference->WithMetadataValue('IsSharedSource', 'true'))" />
88-
<!-- TODO: remove Newtonsoft.Json from this list once https://github.com/aspnet/AspNetCore/issues/4260 is resolved -->
8987
<_OriginalReferences Include="@(Reference)" />
9088
<!--
9189
Turn Reference items into a ProjectReference when UseProjectReferences is true.

src/SignalR/clients/csharp/Client.Core/ref/Microsoft.AspNetCore.SignalR.Client.Core.csproj

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,15 +6,15 @@
66
<ItemGroup Condition="'$(TargetFramework)' == 'netstandard2.0'">
77
<Compile Include="Microsoft.AspNetCore.SignalR.Client.Core.netstandard2.0.cs" />
88
<Reference Include="Microsoft.AspNetCore.SignalR.Common" />
9-
<Reference Include="Microsoft.AspNetCore.SignalR.Protocols.NewtonsoftJson" />
9+
<Reference Include="Microsoft.AspNetCore.SignalR.Protocols.Json" />
1010
<Reference Include="Microsoft.Extensions.DependencyInjection" />
1111
<Reference Include="Microsoft.Extensions.Logging" />
1212
<Reference Include="System.Threading.Channels" />
1313
</ItemGroup>
1414
<ItemGroup Condition="'$(TargetFramework)' == 'netcoreapp3.0'">
1515
<Compile Include="Microsoft.AspNetCore.SignalR.Client.Core.netcoreapp3.0.cs" />
1616
<Reference Include="Microsoft.AspNetCore.SignalR.Common" />
17-
<Reference Include="Microsoft.AspNetCore.SignalR.Protocols.NewtonsoftJson" />
17+
<Reference Include="Microsoft.AspNetCore.SignalR.Protocols.Json" />
1818
<Reference Include="Microsoft.Extensions.DependencyInjection" />
1919
<Reference Include="Microsoft.Extensions.Logging" />
2020
<Reference Include="System.Threading.Channels" />

src/SignalR/clients/csharp/Client.Core/src/HubConnectionBuilder.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ public HubConnectionBuilder()
2525
Services = new ServiceCollection();
2626
Services.AddSingleton<HubConnection>();
2727
Services.AddLogging();
28-
this.AddNewtonsoftJsonProtocol();
28+
this.AddJsonProtocol();
2929
}
3030

3131
/// <inheritdoc />

src/SignalR/clients/csharp/Client.Core/src/Microsoft.AspNetCore.SignalR.Client.Core.csproj

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
<Project Sdk="Microsoft.NET.Sdk">
1+
<Project Sdk="Microsoft.NET.Sdk">
22

33
<PropertyGroup>
44
<Description>Client for ASP.NET Core SignalR</Description>
@@ -22,7 +22,7 @@
2222

2323
<ItemGroup>
2424
<Reference Include="Microsoft.AspNetCore.SignalR.Common" />
25-
<Reference Include="Microsoft.AspNetCore.SignalR.Protocols.NewtonsoftJson" />
25+
<Reference Include="Microsoft.AspNetCore.SignalR.Protocols.Json" />
2626
<Reference Include="Microsoft.Extensions.DependencyInjection" />
2727
<Reference Include="Microsoft.Extensions.Logging" />
2828
<Reference Include="System.Threading.Channels" />

src/SignalR/clients/csharp/Client/test/FunctionalTests/HubConnectionTests.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1014,7 +1014,7 @@ bool ExpectedErrors(WriteContext writeContext)
10141014
}
10151015
}
10161016

1017-
[Theory]
1017+
[Theory(Skip = "Will be fixed by https://github.com/dotnet/corefx/issues/36901")]
10181018
[MemberData(nameof(HubProtocolsAndTransportsAndHubPaths))]
10191019
public async Task ServerThrowsHubExceptionOnHubMethodArgumentTypeMismatch(string hubProtocolName, HttpTransportType transportType, string hubPath)
10201020
{

src/SignalR/clients/ts/FunctionalTests/ComplexObject.cs

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,6 @@ public class ComplexObject
1010
public string String { get; set; }
1111
public int[] IntArray { get; set; }
1212
public byte[] ByteArray { get; set; }
13-
public Guid GUID { get; set; }
1413
public DateTime DateTime { get;set; }
1514
}
1615
}

src/SignalR/clients/ts/FunctionalTests/Startup.cs

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -41,12 +41,6 @@ public void ConfigureServices(IServiceCollection services)
4141
{
4242
options.EnableDetailedErrors = true;
4343
})
44-
.AddNewtonsoftJsonProtocol(options =>
45-
{
46-
// we are running the same tests with JSON and MsgPack protocols and having
47-
// consistent casing makes it cleaner to verify results
48-
options.PayloadSerializerSettings.ContractResolver = new DefaultContractResolver();
49-
})
5044
.AddMessagePackProtocol();
5145

5246
services.AddCors();

src/SignalR/clients/ts/FunctionalTests/TestHub.cs

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -125,7 +125,6 @@ public ComplexObject SendComplexObject()
125125
{
126126
ByteArray = new byte[] { 0x1, 0x2, 0x3 },
127127
DateTime = new DateTime(2000, 1, 1, 0, 0, 0, DateTimeKind.Utc),
128-
GUID = new Guid("00010203-0405-0607-0706-050403020100"),
129128
IntArray = new int[] { 1, 2, 3 },
130129
String = "hello world",
131130
};

src/SignalR/clients/ts/FunctionalTests/ts/HubConnectionTests.ts

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -457,12 +457,11 @@ describe("hubConnection", () => {
457457

458458
const complexObject = {
459459
ByteArray: protocol.name === "json"
460-
? "aGVsbG8="
460+
? new Array(0x68, 0x65, 0x6c, 0x6c, 0x6f)
461461
: new Uint8Array([0x68, 0x65, 0x6c, 0x6c, 0x6f]),
462462
DateTime: protocol.name === "json"
463463
? "2002-04-01T10:20:15Z"
464464
: new Date(Date.UTC(2002, 3, 1, 10, 20, 15)), // Apr 1, 2002, 10:20:15am UTC
465-
GUID: "00010203-0405-0607-0706-050403020100",
466465
IntArray: [0x01, 0x02, 0x03, 0xff],
467466
String: "Hello, World!",
468467
};
@@ -500,12 +499,11 @@ describe("hubConnection", () => {
500499

501500
const complexObject = {
502501
ByteArray: protocol.name === "json"
503-
? "AQID"
502+
? new Array(0x1, 0x2, 0x3)
504503
: new Uint8Array([0x1, 0x2, 0x3]),
505504
DateTime: protocol.name === "json"
506505
? "2000-01-01T00:00:00Z"
507506
: new Date(Date.UTC(2000, 0, 1)),
508-
GUID: "00010203-0405-0607-0706-050403020100",
509507
IntArray: [0x01, 0x02, 0x03],
510508
String: "hello world",
511509
};

src/SignalR/common/Protocols.Json/ref/Microsoft.AspNetCore.SignalR.Protocols.Json.netcoreapp3.0.cs

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,22 @@
11
// Copyright (c) .NET Foundation. All rights reserved.
22
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
33

4+
namespace Microsoft.AspNetCore.SignalR
5+
{
6+
public partial class JsonHubProtocolOptions
7+
{
8+
public JsonHubProtocolOptions() { }
9+
public bool AllowTrailingCommas { get { throw null; } set { } }
10+
public bool IgnoreNullValues { get { throw null; } set { } }
11+
public bool WriteIndented { get { throw null; } set { } }
12+
}
13+
}
414
namespace Microsoft.AspNetCore.SignalR.Protocol
515
{
616
public sealed partial class JsonHubProtocol : Microsoft.AspNetCore.SignalR.Protocol.IHubProtocol
717
{
818
public JsonHubProtocol() { }
19+
public JsonHubProtocol(Microsoft.Extensions.Options.IOptions<Microsoft.AspNetCore.SignalR.JsonHubProtocolOptions> options) { }
920
public int MinorVersion { get { throw null; } }
1021
public string Name { get { throw null; } }
1122
public Microsoft.AspNetCore.Connections.TransferFormat TransferFormat { get { throw null; } }
@@ -21,5 +32,6 @@ namespace Microsoft.Extensions.DependencyInjection
2132
public static partial class JsonProtocolDependencyInjectionExtensions
2233
{
2334
public static TBuilder AddJsonProtocol<TBuilder>(this TBuilder builder) where TBuilder : Microsoft.AspNetCore.SignalR.ISignalRBuilder { throw null; }
35+
public static TBuilder AddJsonProtocol<TBuilder>(this TBuilder builder, System.Action<Microsoft.AspNetCore.SignalR.JsonHubProtocolOptions> configure) where TBuilder : Microsoft.AspNetCore.SignalR.ISignalRBuilder { throw null; }
2436
}
2537
}

src/SignalR/common/Protocols.Json/ref/Microsoft.AspNetCore.SignalR.Protocols.Json.netstandard2.0.cs

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,22 @@
11
// Copyright (c) .NET Foundation. All rights reserved.
22
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
33

4+
namespace Microsoft.AspNetCore.SignalR
5+
{
6+
public partial class JsonHubProtocolOptions
7+
{
8+
public JsonHubProtocolOptions() { }
9+
public bool AllowTrailingCommas { get { throw null; } set { } }
10+
public bool IgnoreNullValues { get { throw null; } set { } }
11+
public bool WriteIndented { get { throw null; } set { } }
12+
}
13+
}
414
namespace Microsoft.AspNetCore.SignalR.Protocol
515
{
616
public sealed partial class JsonHubProtocol : Microsoft.AspNetCore.SignalR.Protocol.IHubProtocol
717
{
818
public JsonHubProtocol() { }
19+
public JsonHubProtocol(Microsoft.Extensions.Options.IOptions<Microsoft.AspNetCore.SignalR.JsonHubProtocolOptions> options) { }
920
public int MinorVersion { get { throw null; } }
1021
public string Name { get { throw null; } }
1122
public Microsoft.AspNetCore.Connections.TransferFormat TransferFormat { get { throw null; } }
@@ -21,5 +32,6 @@ namespace Microsoft.Extensions.DependencyInjection
2132
public static partial class JsonProtocolDependencyInjectionExtensions
2233
{
2334
public static TBuilder AddJsonProtocol<TBuilder>(this TBuilder builder) where TBuilder : Microsoft.AspNetCore.SignalR.ISignalRBuilder { throw null; }
35+
public static TBuilder AddJsonProtocol<TBuilder>(this TBuilder builder, System.Action<Microsoft.AspNetCore.SignalR.JsonHubProtocolOptions> configure) where TBuilder : Microsoft.AspNetCore.SignalR.ISignalRBuilder { throw null; }
2436
}
2537
}
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
// Copyright (c) .NET Foundation. All rights reserved.
2+
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
3+
4+
using System.Text.Json.Serialization;
5+
using Microsoft.AspNetCore.SignalR.Protocol;
6+
7+
namespace Microsoft.AspNetCore.SignalR
8+
{
9+
/// <summary>
10+
/// Options used to configure a <see cref="JsonHubProtocolOptions"/> instance.
11+
/// </summary>
12+
public class JsonHubProtocolOptions
13+
{
14+
internal readonly JsonSerializerOptions _serializerOptions;
15+
16+
public JsonHubProtocolOptions()
17+
{
18+
_serializerOptions = JsonHubProtocol.CreateDefaultSerializerSettings();
19+
}
20+
21+
public bool IgnoreNullValues { get => _serializerOptions.IgnoreNullValues; set => _serializerOptions.IgnoreNullValues = value; }
22+
public bool WriteIndented { get => _serializerOptions.WriteIndented; set => _serializerOptions.WriteIndented = value; }
23+
public bool AllowTrailingCommas { get => _serializerOptions.AllowTrailingCommas; set => _serializerOptions.AllowTrailingCommas = value; }
24+
}
25+
}

src/SignalR/common/Protocols.Json/src/JsonProtocolDependencyInjectionExtensions.cs

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
// Copyright (c) .NET Foundation. All rights reserved.
22
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
33

4+
using System;
45
using Microsoft.AspNetCore.SignalR;
56
using Microsoft.AspNetCore.SignalR.Protocol;
67
using Microsoft.Extensions.DependencyInjection.Extensions;
@@ -21,8 +22,21 @@ public static class JsonProtocolDependencyInjectionExtensions
2122
/// <param name="builder">The <see cref="ISignalRBuilder"/> representing the SignalR server to add JSON protocol support to.</param>
2223
/// <returns>The value of <paramref name="builder"/></returns>
2324
public static TBuilder AddJsonProtocol<TBuilder>(this TBuilder builder) where TBuilder : ISignalRBuilder
25+
=> AddJsonProtocol(builder, _ => { });
26+
27+
/// <summary>
28+
/// Enables the JSON protocol for SignalR and allows options for the JSON protocol to be configured.
29+
/// </summary>
30+
/// <remarks>
31+
/// Any options configured here will be applied, even if the JSON protocol has already been registered with the server.
32+
/// </remarks>
33+
/// <param name="builder">The <see cref="ISignalRBuilder"/> representing the SignalR server to add JSON protocol support to.</param>
34+
/// <param name="configure">A delegate that can be used to configure the <see cref="JsonHubProtocolOptions"/></param>
35+
/// <returns>The value of <paramref name="builder"/></returns>
36+
public static TBuilder AddJsonProtocol<TBuilder>(this TBuilder builder, Action<JsonHubProtocolOptions> configure) where TBuilder : ISignalRBuilder
2437
{
2538
builder.Services.TryAddEnumerable(ServiceDescriptor.Singleton<IHubProtocol, JsonHubProtocol>());
39+
builder.Services.Configure(configure);
2640
return builder;
2741
}
2842
}

src/SignalR/common/Protocols.Json/src/Microsoft.AspNetCore.SignalR.Protocols.Json.csproj

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@
2121
<Reference Include="Microsoft.AspNetCore.SignalR.Common" />
2222
</ItemGroup>
2323

24-
<ItemGroup Condition="'$(TargetFramework)' == 'netstandard2.0'" >
24+
<ItemGroup Condition="'$(TargetFramework)' == 'netstandard2.0'">
2525
<Reference Include="Microsoft.Bcl.Json.Sources" />
2626
<Reference Include="System.Buffers" />
2727
<Reference Include="System.Runtime.CompilerServices.Unsafe" />

src/SignalR/common/Protocols.Json/src/Protocol/JsonHubProtocol.cs

Lines changed: 35 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
using System.Text.Json.Serialization;
1111
using Microsoft.AspNetCore.Connections;
1212
using Microsoft.AspNetCore.Internal;
13+
using Microsoft.Extensions.Options;
1314

1415
namespace Microsoft.AspNetCore.SignalR.Protocol
1516
{
@@ -42,11 +43,25 @@ public sealed class JsonHubProtocol : IHubProtocol
4243
private static readonly int ProtocolVersion = 1;
4344
private static readonly int ProtocolMinorVersion = 0;
4445

46+
/// <summary>
47+
/// Gets the serializer used to serialize invocation arguments and return values.
48+
/// </summary>
49+
private readonly JsonSerializerOptions _payloadSerializerOptions;
50+
51+
/// <summary>
52+
/// Initializes a new instance of the <see cref="JsonHubProtocol"/> class.
53+
/// </summary>
54+
public JsonHubProtocol() : this(Options.Create(new JsonHubProtocolOptions()))
55+
{
56+
}
57+
4558
/// <summary>
4659
/// Initializes a new instance of the <see cref="JsonHubProtocol"/> class.
4760
/// </summary>
48-
public JsonHubProtocol()
61+
/// <param name="options">The options used to initialize the protocol.</param>
62+
public JsonHubProtocol(IOptions<JsonHubProtocolOptions> options)
4963
{
64+
_payloadSerializerOptions = options.Value._serializerOptions;
5065
}
5166

5267
/// <inheritdoc />
@@ -188,11 +203,8 @@ private HubMessage ParseMessage(ReadOnlySequence<byte> input, IInvocationBinder
188203
{
189204
// If we have an invocation id already we can parse the end result
190205
var returnType = binder.GetReturnType(invocationId);
191-
if (reader.TokenType != JsonTokenType.Null)
192-
{
193-
using var token = JsonDocument.ParseValue(ref reader);
194-
result = BindType(token.RootElement, returnType);
195-
}
206+
using var token = JsonDocument.ParseValue(ref reader);
207+
result = BindType(token.RootElement, returnType);
196208
}
197209
}
198210
else if (reader.TextEquals(ItemPropertyNameBytes))
@@ -216,11 +228,8 @@ private HubMessage ParseMessage(ReadOnlySequence<byte> input, IInvocationBinder
216228
try
217229
{
218230
var itemType = binder.GetStreamItemType(id);
219-
if (reader.TokenType != JsonTokenType.Null)
220-
{
221-
using var token = JsonDocument.ParseValue(ref reader);
222-
item = BindType(token.RootElement, itemType);
223-
}
231+
using var token = JsonDocument.ParseValue(ref reader);
232+
item = BindType(token.RootElement, itemType);
224233
}
225234
catch (Exception ex)
226235
{
@@ -571,7 +580,7 @@ private void WriteArguments(object[] arguments, ref Utf8JsonWriter writer)
571580

572581
private JsonDocument GetParsedObject(object obj, Type type)
573582
{
574-
var bytes = JsonSerializer.ToBytes(obj, type);
583+
var bytes = JsonSerializer.ToBytes(obj, type, _payloadSerializerOptions);
575584
var token = JsonDocument.Parse(bytes);
576585
return token;
577586
}
@@ -695,11 +704,7 @@ private object BindType(JsonElement jsonObject, Type type)
695704
return jsonObject.GetDateTimeOffset();
696705
}
697706

698-
if (jsonObject.Type == JsonValueType.Null)
699-
{
700-
return null;
701-
}
702-
return JsonSerializer.Parse(jsonObject.GetRawText(), type);
707+
return JsonSerializer.Parse(jsonObject.GetRawText(), type, _payloadSerializerOptions);
703708
}
704709

705710
private object[] BindTypes(JsonElement jsonArray, IReadOnlyList<Type> paramTypes)
@@ -756,5 +761,18 @@ private HubMessage ApplyHeaders(HubMessage message, Dictionary<string, string> h
756761

757762
return message;
758763
}
764+
765+
internal static JsonSerializerOptions CreateDefaultSerializerSettings()
766+
{
767+
var options = new JsonSerializerOptions();
768+
options.WriteIndented = false;
769+
options.ReadCommentHandling = JsonCommentHandling.Disallow;
770+
options.AllowTrailingCommas = false;
771+
options.IgnoreNullValues = false;
772+
options.IgnoreReadOnlyProperties = false;
773+
// TODO: camelCase
774+
775+
return options;
776+
}
759777
}
760778
}

src/SignalR/common/Protocols.NewtonsoftJson/src/Microsoft.AspNetCore.SignalR.Protocols.NewtonsoftJson.csproj

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,6 @@
33
<PropertyGroup>
44
<Description>Implements the SignalR Hub Protocol using Newtonsoft.Json.</Description>
55
<TargetFramework>netstandard2.0</TargetFramework>
6-
<!-- TODO: remove this from the shared framework once we have a JSON protocol implementation which doesn't use Newtonsoft.Json. -->
7-
<IsAspNetCoreApp>true</IsAspNetCoreApp>
86
<RootNamespace>Microsoft.AspNetCore.SignalR</RootNamespace>
97
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
108
<IsShippingPackage>true</IsShippingPackage>

0 commit comments

Comments
 (0)