Skip to content

Commit

Permalink
Add Newtonsoft CamelCase config support
Browse files Browse the repository at this point in the history
Allow to use "Azure:SignalR:HubProtocol:Newtonsoft:CamelCase=true" to enable camelcase.
  • Loading branch information
Y-Sindo committed Jun 23, 2021
1 parent 1ff15af commit 8ec2bfa
Show file tree
Hide file tree
Showing 3 changed files with 80 additions and 18 deletions.
43 changes: 25 additions & 18 deletions src/SignalRServiceExtension/Config/DependencyInjectionExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,31 +2,43 @@
// 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
{
internal static class DependencyInjectionExtensions
{
private const string HubProtocolError = "It's invalid to configure hub protocol on Azure Functions runtime V2. Newtonsoft.Json protocol will be used.";
private const string HubProtocolError = "It's invalid to set hub protocol to System.Text.Json on Azure Functions runtime V2.";

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 != null)
{
// Actually is .Net Core 2.x
throw new InvalidOperationException(HubProtocolError);
var hubProtocol = Enum.Parse<HubProtocol>(hubProtocolConfig);
if (Environment.Version.Major == 4 && hubProtocol == HubProtocol.SystemTextJson)
{
// .Net Core 2.x is always Newtonsoft.Json.
throw new InvalidOperationException(HubProtocolError);
}
//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.
if (!DotnetRuntime(configuration) || hubProtocol == HubProtocol.NewtonsoftJson)
{
if (configuration.GetValue(Constants.AzureSignalRNewtonsoftCamelCase, false))
{
// The default options is camelCase.
services.AddNewtonsoftHubProtocol(o => { });
}
else
{
// Reset the options to keep backward compatibility.
services.AddNewtonsoftHubProtocol(o => o.PayloadSerializerSettings = new JsonSerializerSettings());
}
}
}
#if NETCOREAPP3_1 || NETCOREAPP3_0 || NETSTANDARD2_0
else if (!DotnetRuntime(configuration) || UserSpecifyNewtonsoft(configuration))
{
// .Net Core 3.1, overwrite the System.Text.Json Protocol.
services.TryAddEnumerable(ServiceDescriptor.Singleton<IHubProtocol, NewtonsoftJsonHubProtocol>());
}
#endif
return services;
}

Expand All @@ -36,10 +48,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 const string AzureSignalRNewtonsoftCamelCase = "Azure:SignalR:HubProtocol:Newtonsoft:CamelCase";
public const string ServiceTransportTypeName = "AzureSignalRServiceTransportType";
public const string AsrsHeaderPrefix = "X-ASRS-";
public const string AsrsConnectionIdHeader = AsrsHeaderPrefix + "Connection-Id";
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,17 @@

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
Expand All @@ -22,6 +29,18 @@ public void EmptyHubProtocolSetting_DoNothing()
Assert.Empty(services);
}

[Fact]
public async Task SetNewtonsoftCamelCaseInTransientModeAsync()
{
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.IsType<CamelCasePropertyNamesContractResolver>(newtonsoftOptions.Value.PayloadSerializerSettings.ContractResolver);
}

#if NETCOREAPP2_1

[Fact]
Expand All @@ -33,6 +52,19 @@ public void SetHubProtocol_Throw()
Assert.Throws<InvalidOperationException>(() => services.SetHubProtocol(configuration));
}

[Fact]
public async Task SetNewtonsoftCamelCaseInPersistentModeAsync()
{
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>();
// on .Net Core 2.1, JsonHubProtocol stands for Newtonsoft.Json protocol
Assert.IsType<JsonHubProtocol>(hubProtocol);
var newtonsoftOptions = hubContext.ServiceProvider.GetRequiredService<IOptions<JsonHubProtocolOptions>>();
Assert.IsType<CamelCasePropertyNamesContractResolver>(newtonsoftOptions.Value.PayloadSerializerSettings.ContractResolver);
}

#endif

#if NETCOREAPP3_1
Expand All @@ -57,6 +89,28 @@ public void SetNewtonsoft()
var hubProtocolImpl = services.Single().ImplementationType;
Assert.Equal(typeof(NewtonsoftJsonHubProtocol), hubProtocolImpl);
}

[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.IsType<CamelCasePropertyNamesContractResolver>(newtonsoftOptions.Value.PayloadSerializerSettings.ContractResolver);
}
#endif

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

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

0 comments on commit 8ec2bfa

Please sign in to comment.