Skip to content

Commit

Permalink
Add Newtonsoft CamelCase config support (#248)
Browse files Browse the repository at this point in the history
Allow to use "Azure:SignalR:HubProtocol:Newtonsoft:CamelCase=true" to enable camelcase.

If user want NewtonsoftCamelCase, no need set “HubProtocol=NewtonsoftJson". "HubProtocol:NewtonsoftJson:CamelCase=true" implies Newtonsoft already.
  • Loading branch information
Y-Sindo committed Jun 30, 2021
1 parent f6390ad commit 16cff13
Show file tree
Hide file tree
Showing 4 changed files with 137 additions and 76 deletions.
32 changes: 18 additions & 14 deletions src/SignalRServiceExtension/Config/DependencyInjectionExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,10 @@
// Licensed under the MIT license. See LICENSE file in the project root for full license information.

using System;
using Microsoft.AspNetCore.SignalR.Protocol;
using Microsoft.Azure.SignalR.Management;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.DependencyInjection.Extensions;
using Newtonsoft.Json;

namespace Microsoft.Azure.WebJobs.Extensions.SignalRService
{
Expand All @@ -15,18 +15,27 @@ internal static class DependencyInjectionExtensions

public static IServiceCollection SetHubProtocol(this IServiceCollection services, IConfiguration configuration)
{
if (Environment.Version.Major == 4 && configuration[Constants.AzureSignalRHubProtocol] != null)
var hubProtocolConfig = configuration[Constants.AzureSignalRHubProtocol];
if (hubProtocolConfig is not null && Environment.Version.Major == 4)
{
// Actually is .Net Core 2.x
// .Net Core 2.x is always Newtonsoft.Json.
throw new InvalidOperationException(HubProtocolError);
}
#if NETCOREAPP3_1 || NETCOREAPP3_0 || NETSTANDARD2_0
else if (!DotnetRuntime(configuration) || UserSpecifyNewtonsoft(configuration))

//indicates Newtonsoft, camcelCase
if (configuration.GetValue(Constants.AzureSignalRNewtonsoftCamelCase, false))
{
// .Net Core 3.1, overwrite the System.Text.Json Protocol.
services.TryAddEnumerable(ServiceDescriptor.Singleton<IHubProtocol, NewtonsoftJsonHubProtocol>());
// The default options is camelCase.
return services.AddNewtonsoftHubProtocol(o => { });
}
#endif

if (!DotnetRuntime(configuration) || Enum.TryParse<HubProtocol>(hubProtocolConfig, out var result) && result == HubProtocol.NewtonsoftJson)
{
// Reset the options to keep backward compatibility.
return services.AddNewtonsoftHubProtocol(o => o.PayloadSerializerSettings = new JsonSerializerSettings());
}

//If hubProtocolConfig is SystemTextJson for .Net Core 3.1, do nothing, as transient mode doesn't accept it and persisent mode is already System.Text.Json by default.
return services;
}

Expand All @@ -36,10 +45,5 @@ private static bool DotnetRuntime(IConfiguration configuration)
//unit test environment
return workerRuntime == null || workerRuntime == Constants.DotnetWorker;
}

private static bool UserSpecifyNewtonsoft(IConfiguration configuration)
{
return configuration.GetValue(Constants.AzureSignalRHubProtocol, HubProtocol.SystemTextJson) == HubProtocol.NewtonsoftJson;
}
}
}
1 change: 1 addition & 0 deletions src/SignalRServiceExtension/Constants.cs
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ internal static class Constants
public const string AzureSignalRConnectionStringName = "AzureSignalRConnectionString";
public const string AzureSignalREndpoints = "Azure:SignalR:Endpoints";
public const string AzureSignalRHubProtocol = "Azure:SignalR:HubProtocol";
public static string AzureSignalRNewtonsoftCamelCase = $"{AzureSignalRHubProtocol}:{HubProtocol.NewtonsoftJson}:CamelCase";
public const string ServiceTransportTypeName = "AzureSignalRServiceTransportType";
public const string AsrsHeaderPrefix = "X-ASRS-";
public const string AsrsConnectionIdHeader = AsrsHeaderPrefix + "Connection-Id";
Expand Down

This file was deleted.

Original file line number Diff line number Diff line change
@@ -0,0 +1,118 @@
// Copyright (c) Microsoft. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.

using System;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.SignalR;
using Microsoft.AspNetCore.SignalR.Protocol;
using Microsoft.Azure.SignalR.Management;
using Microsoft.Azure.SignalR.Tests.Common;
using Microsoft.Azure.WebJobs.Extensions.SignalRService;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging.Abstractions;
using Microsoft.Extensions.Options;
using Newtonsoft.Json.Serialization;
using Xunit;

namespace SignalRServiceExtension.Tests
{
public class SetNewtonsoftHubProtocolFacts
{
[Fact]
public void EmptyHubProtocolSetting_DoNothing()
{
var configuration = new ConfigurationBuilder().AddInMemoryCollection().Build();
var services = new ServiceCollection()
.SetHubProtocol(configuration);
Assert.Empty(services);
}

#if NETCOREAPP2_1

[Fact]
public void SetHubProtocol_Throw()
{
var configuration = new ConfigurationBuilder().AddInMemoryCollection().Build();
configuration[Constants.AzureSignalRHubProtocol] = HubProtocol.SystemTextJson.ToString();
var services = new ServiceCollection();
Assert.Throws<InvalidOperationException>(() => services.SetHubProtocol(configuration));
}

#endif

#if NETCOREAPP3_1

[Fact]
public void SetSystemTextJson_DoNothing()
{
var configuration = new ConfigurationBuilder().AddInMemoryCollection().Build();
configuration[Constants.AzureSignalRHubProtocol] = HubProtocol.SystemTextJson.ToString();
var services = new ServiceCollection()
.SetHubProtocol(configuration);
Assert.Empty(services);
}

[Fact]
public async Task SetNewtonsoftPersistent()
{
var serviceManagerStore = CreateServiceManagerStore(out var configuration);
configuration[Constants.ServiceTransportTypeName] = "Persistent";
var hubContext = await serviceManagerStore.GetOrAddByConnectionStringKey(Constants.AzureSignalRConnectionStringName).GetAsync("hub") as ServiceHubContextImpl;
var hubProtocol = hubContext.ServiceProvider.GetRequiredService<IHubProtocol>();
Assert.IsType<NewtonsoftJsonHubProtocol>(hubProtocol);
var newtonsoftOptions = hubContext.ServiceProvider.GetRequiredService<IOptions<NewtonsoftJsonHubProtocolOptions>>();
Assert.Null(newtonsoftOptions.Value.PayloadSerializerSettings.ContractResolver);
}

[Fact]
public async Task SetNewtonsoftInTransientModeAsync()
{
var serviceManagerStore = CreateServiceManagerStore(out var configuration);
var hubContext = await serviceManagerStore.GetOrAddByConnectionStringKey(Constants.AzureSignalRConnectionStringName).GetAsync("hub") as ServiceHubContextImpl;

var restHubProtocol = hubContext.ServiceProvider.GetRequiredService<IRestHubProtocol>();
Assert.IsType<NewtonsoftRestHubProtocol>(restHubProtocol);
var newtonsoftOptions = hubContext.ServiceProvider.GetRequiredService<IOptions<NewtonsoftServiceHubProtocolOptions>>();
Assert.Null(newtonsoftOptions.Value.PayloadSerializerSettings.ContractResolver);
}

[Fact]
public async Task SetNewtonsoftCamelCaseInTransientModeAsync()
{
var serviceManagerStore = CreateServiceManagerStore(out var configuration);
configuration["Azure:SignalR:HubProtocol:NewtonsoftJson:CamelCase"] = "true";

var hubContext = await serviceManagerStore.GetOrAddByConnectionStringKey(Constants.AzureSignalRConnectionStringName).GetAsync("hub") as ServiceHubContextImpl;
var restHubProtocol = hubContext.ServiceProvider.GetRequiredService<IRestHubProtocol>();
Assert.IsType<NewtonsoftRestHubProtocol>(restHubProtocol);
var newtonsoftOptions = hubContext.ServiceProvider.GetRequiredService<IOptions<NewtonsoftServiceHubProtocolOptions>>();
Assert.IsType<CamelCasePropertyNamesContractResolver>(newtonsoftOptions.Value.PayloadSerializerSettings.ContractResolver);
}

[Fact]
public async Task SetNewtonsoftCamelCaseInPersistentModeAsync()
{
var serviceManagerStore = CreateServiceManagerStore(out var configuration);
configuration["Azure:SignalR:HubProtocol:NewtonsoftJson:CamelCase"] = "true";
configuration[Constants.ServiceTransportTypeName] = "Persistent";

var hubContext = await serviceManagerStore.GetOrAddByConnectionStringKey(Constants.AzureSignalRConnectionStringName).GetAsync("hub") as ServiceHubContextImpl;
var hubProtocol = hubContext.ServiceProvider.GetRequiredService<IHubProtocol>();
Assert.IsType<NewtonsoftJsonHubProtocol>(hubProtocol);
var newtonsoftOptions = hubContext.ServiceProvider.GetRequiredService<IOptions<NewtonsoftJsonHubProtocolOptions>>();
Assert.IsType<CamelCasePropertyNamesContractResolver>(newtonsoftOptions.Value.PayloadSerializerSettings.ContractResolver);
}

private ServiceManagerStore CreateServiceManagerStore(out IConfiguration configuration)
{
configuration = new ConfigurationBuilder().AddInMemoryCollection().Build();
configuration[Constants.AzureSignalRHubProtocol] = HubProtocol.NewtonsoftJson.ToString();
configuration[Constants.AzureSignalRConnectionStringName] = FakeEndpointUtils.GetFakeConnectionString(1).Single();

return new ServiceManagerStore(configuration, NullLoggerFactory.Instance, null);
}
#endif
}
}

0 comments on commit 16cff13

Please sign in to comment.