Enabling customizing serialization settings in MessagePack protocol
This commit is contained in:
parent
20d4d70cc7
commit
ba25dee141
|
|
@ -23,7 +23,8 @@ namespace Microsoft.AspNetCore.SignalR.Client
|
|||
|
||||
public static IHubConnectionBuilder WithMessagePackProtocol(this IHubConnectionBuilder hubConnectionBuilder)
|
||||
{
|
||||
return hubConnectionBuilder.WithHubProtocol(new MessagePackHubProtocol());
|
||||
return hubConnectionBuilder.WithHubProtocol(
|
||||
new MessagePackHubProtocol(MessagePackHubProtocol.CreateDefaultSerializationContext()));
|
||||
}
|
||||
|
||||
public static IHubConnectionBuilder WithLoggerFactory(this IHubConnectionBuilder hubConnectionBuilder, ILoggerFactory loggerFactory)
|
||||
|
|
|
|||
|
|
@ -20,18 +20,15 @@ namespace Microsoft.AspNetCore.SignalR.Internal.Protocol
|
|||
private const int VoidResult = 2;
|
||||
private const int NonVoidResult = 3;
|
||||
|
||||
private static readonly SerializationContext _serializationContext;
|
||||
private readonly SerializationContext _serializationContext;
|
||||
|
||||
public string Name => "messagepack";
|
||||
|
||||
public ProtocolType Type => ProtocolType.Binary;
|
||||
|
||||
static MessagePackHubProtocol()
|
||||
public MessagePackHubProtocol(SerializationContext serializationContext)
|
||||
{
|
||||
// serializes objects (here: arguments and results) as maps so that property names are preserved
|
||||
_serializationContext = new SerializationContext { SerializationMethod = SerializationMethod.Map };
|
||||
// allows for serializing objects that cannot be deserialized due to the lack of the default ctor etc.
|
||||
_serializationContext.CompatibilityOptions.AllowAsymmetricSerializer = true;
|
||||
_serializationContext = serializationContext;
|
||||
}
|
||||
|
||||
public bool TryParseMessages(ReadOnlyBuffer<byte> input, IInvocationBinder binder, out IList<HubMessage> messages)
|
||||
|
|
@ -156,7 +153,7 @@ namespace Microsoft.AspNetCore.SignalR.Internal.Protocol
|
|||
}
|
||||
}
|
||||
|
||||
private static void WriteInvocationMessage(InvocationMessage invocationMessage, Packer packer, Stream output)
|
||||
private void WriteInvocationMessage(InvocationMessage invocationMessage, Packer packer, Stream output)
|
||||
{
|
||||
packer.PackArrayHeader(5);
|
||||
packer.Pack(InvocationMessageType);
|
||||
|
|
@ -291,5 +288,15 @@ namespace Microsoft.AspNetCore.SignalR.Internal.Protocol
|
|||
|
||||
throw new FormatException($"Deserializing object of the `{type.Name}` type for '{field}' failed.", msgPackException);
|
||||
}
|
||||
|
||||
public static SerializationContext CreateDefaultSerializationContext()
|
||||
{
|
||||
// serializes objects (here: arguments and results) as maps so that property names are preserved
|
||||
var serializationContext = new SerializationContext { SerializationMethod = SerializationMethod.Map };
|
||||
// allows for serializing objects that cannot be deserialized due to the lack of the default ctor etc.
|
||||
serializationContext.CompatibilityOptions.AllowAsymmetricSerializer = true;
|
||||
|
||||
return serializationContext;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,6 +1,8 @@
|
|||
// Copyright (c) .NET Foundation. All rights reserved.
|
||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||
|
||||
using Microsoft.AspNetCore.SignalR.Internal.Protocol;
|
||||
using MsgPack.Serialization;
|
||||
using Newtonsoft.Json;
|
||||
|
||||
namespace Microsoft.AspNetCore.SignalR
|
||||
|
|
@ -8,5 +10,6 @@ namespace Microsoft.AspNetCore.SignalR
|
|||
public class HubOptions
|
||||
{
|
||||
public JsonSerializerSettings JsonSerializerSettings { get; set; } = new JsonSerializerSettings();
|
||||
public SerializationContext MessagePackSerializationContext { get; set; } = MessagePackHubProtocol.CreateDefaultSerializationContext();
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -24,7 +24,7 @@ namespace Microsoft.AspNetCore.SignalR.Internal
|
|||
case "json":
|
||||
return new JsonHubProtocol(JsonSerializer.Create(_options.Value.JsonSerializerSettings));
|
||||
case "messagepack":
|
||||
return new MessagePackHubProtocol();
|
||||
return new MessagePackHubProtocol(_options.Value.MessagePackSerializationContext);
|
||||
default:
|
||||
throw new NotSupportedException($"The protocol '{protocolName ?? "(null)"}' is not supported.");
|
||||
}
|
||||
|
|
|
|||
|
|
@ -246,7 +246,7 @@ namespace Microsoft.AspNetCore.SignalR.Client.FunctionalTests
|
|||
new IHubProtocol[]
|
||||
{
|
||||
new JsonHubProtocol(new JsonSerializer()),
|
||||
new MessagePackHubProtocol(),
|
||||
new MessagePackHubProtocol(MessagePackHubProtocol.CreateDefaultSerializationContext()),
|
||||
};
|
||||
|
||||
public static IEnumerable<TransportType> TransportTypes()
|
||||
|
|
|
|||
|
|
@ -331,7 +331,8 @@ namespace Microsoft.AspNetCore.SignalR.Client.Tests
|
|||
{
|
||||
var connection = new TestConnection(TransferMode.Text);
|
||||
|
||||
var hubConnection = new HubConnection(connection, new MessagePackHubProtocol(), new LoggerFactory());
|
||||
var hubConnection = new HubConnection(connection,
|
||||
new MessagePackHubProtocol(MessagePackHubProtocol.CreateDefaultSerializationContext()), new LoggerFactory());
|
||||
try
|
||||
{
|
||||
await hubConnection.StartAsync().OrTimeout();
|
||||
|
|
@ -361,7 +362,8 @@ namespace Microsoft.AspNetCore.SignalR.Client.Tests
|
|||
public async Task MessagesDecodedWhenUsingBinaryProtocolOverTextTransport()
|
||||
{
|
||||
var connection = new TestConnection(TransferMode.Text);
|
||||
var hubConnection = new HubConnection(connection, new MessagePackHubProtocol(), new LoggerFactory());
|
||||
var hubConnection = new HubConnection(connection,
|
||||
new MessagePackHubProtocol(MessagePackHubProtocol.CreateDefaultSerializationContext()), new LoggerFactory());
|
||||
|
||||
var invocationTcs = new TaskCompletionSource<int>();
|
||||
try
|
||||
|
|
@ -371,7 +373,8 @@ namespace Microsoft.AspNetCore.SignalR.Client.Tests
|
|||
|
||||
using (var ms = new MemoryStream())
|
||||
{
|
||||
new MessagePackHubProtocol().WriteMessage(new InvocationMessage("1", true, "MyMethod", 42), ms);
|
||||
new MessagePackHubProtocol(MessagePackHubProtocol.CreateDefaultSerializationContext())
|
||||
.WriteMessage(new InvocationMessage("1", true, "MyMethod", 42), ms);
|
||||
|
||||
var invokeMessage = Convert.ToBase64String(ms.ToArray());
|
||||
var payloadSize = invokeMessage.Length.ToString(CultureInfo.InvariantCulture);
|
||||
|
|
|
|||
|
|
@ -12,7 +12,8 @@ namespace Microsoft.AspNetCore.SignalR.Common.Tests.Internal.Protocol
|
|||
{
|
||||
public class MessagePackHubProtocolTests
|
||||
{
|
||||
private static readonly MessagePackHubProtocol _hubProtocol = new MessagePackHubProtocol();
|
||||
private static readonly MessagePackHubProtocol _hubProtocol
|
||||
= new MessagePackHubProtocol(MessagePackHubProtocol.CreateDefaultSerializationContext());
|
||||
|
||||
public static IEnumerable<object[]> TestMessages => new[]
|
||||
{
|
||||
|
|
|
|||
|
|
@ -13,8 +13,11 @@ using Microsoft.AspNetCore.Http;
|
|||
using Microsoft.AspNetCore.SignalR.Internal.Protocol;
|
||||
using Microsoft.AspNetCore.SignalR.Tests.Common;
|
||||
using Microsoft.AspNetCore.Sockets;
|
||||
using Microsoft.AspNetCore.Sockets.Features;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Moq;
|
||||
using MsgPack;
|
||||
using MsgPack.Serialization;
|
||||
using Newtonsoft.Json;
|
||||
using Newtonsoft.Json.Serialization;
|
||||
using Xunit;
|
||||
|
|
@ -1020,7 +1023,7 @@ namespace Microsoft.AspNetCore.SignalR.Tests
|
|||
|
||||
await client.SendInvocationAsync(nameof(MethodHub.BroadcastItem)).OrTimeout();
|
||||
|
||||
var message = await client.ReadAsync().OrTimeout() as InvocationMessage;
|
||||
var message = (InvocationMessage)await client.ReadAsync().OrTimeout();
|
||||
|
||||
var customItem = message.Arguments[0].ToString();
|
||||
// Originally "Message" and "paramName"
|
||||
|
|
@ -1033,6 +1036,46 @@ namespace Microsoft.AspNetCore.SignalR.Tests
|
|||
}
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task HubOptionsCanUseCustomMessagePackSettings()
|
||||
{
|
||||
var serializationContext = MessagePackHubProtocol.CreateDefaultSerializationContext();
|
||||
serializationContext.SerializationMethod = SerializationMethod.Array;
|
||||
|
||||
var serviceProvider = CreateServiceProvider(services =>
|
||||
{
|
||||
services.AddSignalR(options =>
|
||||
{
|
||||
options.MessagePackSerializationContext = serializationContext;
|
||||
});
|
||||
});
|
||||
|
||||
var endPoint = serviceProvider.GetService<HubEndPoint<MethodHub>>();
|
||||
|
||||
using (var client = new TestClient(synchronousCallbacks: false, protocol: new MessagePackHubProtocol(serializationContext)))
|
||||
{
|
||||
var transportFeature = new Mock<IConnectionTransportFeature>();
|
||||
transportFeature.SetupGet(f => f.TransportCapabilities).Returns(TransferMode.Binary);
|
||||
client.Connection.Features.Set(transportFeature.Object);
|
||||
var endPointLifetime = endPoint.OnConnectedAsync(client.Connection);
|
||||
|
||||
await client.Connected.OrTimeout();
|
||||
|
||||
await client.SendInvocationAsync(nameof(MethodHub.BroadcastItem)).OrTimeout();
|
||||
|
||||
var message = await client.ReadAsync().OrTimeout() as InvocationMessage;
|
||||
|
||||
var msgPackObject = Assert.IsType<MessagePackObject>(message.Arguments[0]);
|
||||
// Custom serialization - object was serialized as an array and not a map
|
||||
Assert.True(msgPackObject.IsArray);
|
||||
Assert.Equal(new[] { "test", "param" }, ((MessagePackObject[])msgPackObject.ToObject()).Select(o => o.AsString()));
|
||||
|
||||
client.Dispose();
|
||||
|
||||
await endPointLifetime.OrTimeout();
|
||||
}
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task CanGetHttpContextFromHubConnectionContext()
|
||||
{
|
||||
|
|
@ -1427,6 +1470,15 @@ namespace Microsoft.AspNetCore.SignalR.Tests
|
|||
}
|
||||
}
|
||||
|
||||
public class Result
|
||||
{
|
||||
public string Message { get; set; }
|
||||
#pragma warning disable IDE1006 // Naming Styles
|
||||
// testing casing
|
||||
public string paramName { get; set; }
|
||||
#pragma warning restore IDE1006 // Naming Styles
|
||||
}
|
||||
|
||||
private class MethodHub : TestHub
|
||||
{
|
||||
public Task GroupRemoveMethod(string groupName)
|
||||
|
|
@ -1461,7 +1513,7 @@ namespace Microsoft.AspNetCore.SignalR.Tests
|
|||
|
||||
public Task BroadcastItem()
|
||||
{
|
||||
return Clients.All.InvokeAsync("Broadcast", new { Message = "test", paramName = "test" });
|
||||
return Clients.All.InvokeAsync("Broadcast", new Result { Message = "test", paramName = "param" });
|
||||
}
|
||||
|
||||
public Task<int> TaskValueMethod()
|
||||
|
|
|
|||
|
|
@ -42,7 +42,7 @@ namespace Microsoft.AspNetCore.SignalR.Common.Protocol.Tests
|
|||
new[]
|
||||
{
|
||||
new object[] { new JsonHubProtocol(new JsonSerializer()) },
|
||||
new object[] { new MessagePackHubProtocol() },
|
||||
new object[] { new MessagePackHubProtocol(MessagePackHubProtocol.CreateDefaultSerializationContext()) },
|
||||
};
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@
|
|||
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Microsoft.Extensions.Options;
|
||||
using MsgPack.Serialization;
|
||||
using Xunit;
|
||||
|
||||
namespace Microsoft.AspNetCore.SignalR.Tests
|
||||
|
|
@ -19,5 +20,19 @@ namespace Microsoft.AspNetCore.SignalR.Tests
|
|||
var hubOptions = serviceProvider.GetService<IOptions<HubOptions>>();
|
||||
Assert.NotNull(hubOptions.Value.JsonSerializerSettings);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void MessagePackSerializationContextInOptionsIsSetAndHasDefaultSettings()
|
||||
{
|
||||
var services = new ServiceCollection();
|
||||
services.AddOptions();
|
||||
services.AddSignalR();
|
||||
var serviceProvider = services.BuildServiceProvider();
|
||||
var hubOptions = serviceProvider.GetService<IOptions<HubOptions>>();
|
||||
var serializationContext = hubOptions.Value.MessagePackSerializationContext;
|
||||
Assert.NotNull(serializationContext);
|
||||
Assert.Equal(SerializationMethod.Map, serializationContext.SerializationMethod);
|
||||
Assert.True(serializationContext.CompatibilityOptions.AllowAsymmetricSerializer);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -28,7 +28,7 @@ namespace Microsoft.AspNetCore.SignalR.Tests
|
|||
public Channel<byte[]> Application { get; }
|
||||
public Task Connected => ((TaskCompletionSource<bool>)Connection.Metadata["ConnectedTask"]).Task;
|
||||
|
||||
public TestClient(bool synchronousCallbacks = false)
|
||||
public TestClient(bool synchronousCallbacks = false, IHubProtocol protocol = null)
|
||||
{
|
||||
var options = new ChannelOptimizations { AllowSynchronousContinuations = synchronousCallbacks };
|
||||
var transportToApplication = Channel.CreateUnbounded<byte[]>(options);
|
||||
|
|
@ -41,7 +41,7 @@ namespace Microsoft.AspNetCore.SignalR.Tests
|
|||
Connection.User = new ClaimsPrincipal(new ClaimsIdentity(new[] { new Claim(ClaimTypes.Name, Interlocked.Increment(ref _id).ToString()) }));
|
||||
Connection.Metadata["ConnectedTask"] = new TaskCompletionSource<bool>();
|
||||
|
||||
var protocol = new JsonHubProtocol(new JsonSerializer());
|
||||
protocol = protocol ?? new JsonHubProtocol(new JsonSerializer());
|
||||
_protocolReaderWriter = new HubProtocolReaderWriter(protocol, new PassThroughEncoder());
|
||||
|
||||
_cts = new CancellationTokenSource();
|
||||
|
|
|
|||
Loading…
Reference in New Issue