diff --git a/build/dependencies.props b/build/dependencies.props
index 2be31c69e3..a73b8b05b6 100644
--- a/build/dependencies.props
+++ b/build/dependencies.props
@@ -57,7 +57,7 @@
2.1.0-preview2-26403-06
15.6.1
4.7.49
- 1.0.0-rc
+ 1.7.3.4
11.0.2
1.2.4
4.5.0-preview2-26403-05
diff --git a/clients/ts/FunctionalTests/ComplexObject.cs b/clients/ts/FunctionalTests/ComplexObject.cs
index 5d471e35e0..d830114fe1 100644
--- a/clients/ts/FunctionalTests/ComplexObject.cs
+++ b/clients/ts/FunctionalTests/ComplexObject.cs
@@ -11,5 +11,6 @@ namespace FunctionalTests
public int[] IntArray { get; set; }
public byte[] ByteArray { get; set; }
public Guid GUID { get; set; }
+ public DateTime DateTime { get;set; }
}
}
diff --git a/clients/ts/FunctionalTests/TestHub.cs b/clients/ts/FunctionalTests/TestHub.cs
index e555408983..c996916277 100644
--- a/clients/ts/FunctionalTests/TestHub.cs
+++ b/clients/ts/FunctionalTests/TestHub.cs
@@ -70,5 +70,17 @@ namespace FunctionalTests
{
return complexObject;
}
+
+ public ComplexObject SendComplexObject()
+ {
+ return new ComplexObject
+ {
+ ByteArray = new byte[] { 0x1, 0x2, 0x3 },
+ DateTime = new DateTime(2000, 1, 1, 0, 0, 0, DateTimeKind.Utc),
+ GUID = new Guid("00010203-0405-0607-0706-050403020100"),
+ IntArray = new int[] { 1, 2, 3 },
+ String = "hello world",
+ };
+ }
}
}
diff --git a/clients/ts/FunctionalTests/ts/HubConnectionTests.ts b/clients/ts/FunctionalTests/ts/HubConnectionTests.ts
index 6f6bcc8a4d..4f6d82cf9c 100644
--- a/clients/ts/FunctionalTests/ts/HubConnectionTests.ts
+++ b/clients/ts/FunctionalTests/ts/HubConnectionTests.ts
@@ -379,9 +379,10 @@ describe("hubConnection", () => {
ByteArray: protocol.name === "json"
? "aGVsbG8="
: new Uint8Array([0x68, 0x65, 0x6c, 0x6c, 0x6f]),
- GUID: protocol.name === "json"
- ? "00010203-0405-0607-0706-050403020100"
- : new Uint8Array([0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x07, 0x06, 0x05, 0x04, 0x03, 0x02, 0x01, 0x00]),
+ DateTime: protocol.name === "json"
+ ? "2002-04-01T10:20:15Z"
+ : new Date(Date.UTC(2002, 3, 1, 10, 20, 15)), // Apr 1, 2002, 10:20:15am UTC
+ GUID: "00010203-0405-0607-0706-050403020100",
IntArray: [0x01, 0x02, 0x03, 0xff],
String: "Hello, World!",
};
@@ -395,9 +396,50 @@ describe("hubConnection", () => {
// msgpack creates a Buffer for byte arrays and jasmine fails to compare a Buffer
// and a Uint8Array even though Buffer instances are also Uint8Array instances
value.ByteArray = new Uint8Array(value.ByteArray);
+ }
+ expect(value).toEqual(complexObject);
+ })
+ .then(() => {
+ hubConnection.stop();
+ })
+ .catch((e) => {
+ fail(e);
+ done();
+ });
+ });
- // GUIDs are serialized as Buffer as well.
- value.GUID = new Uint8Array(value.GUID);
+ it("can receive different types", (done) => {
+ const hubConnection = new HubConnection(TESTHUBENDPOINT_URL, {
+ ...commonOptions,
+ protocol,
+ transport: transportType,
+ });
+ hubConnection.onclose((error) => {
+ expect(error).toBe(undefined);
+ done();
+ });
+
+ const complexObject = {
+ ByteArray: protocol.name === "json"
+ ? "AQID"
+ : new Uint8Array([0x1, 0x2, 0x3]),
+ DateTime: protocol.name === "json"
+ ? "2000-01-01T00:00:00Z"
+ : new Date(Date.UTC(2000, 0, 1)),
+ GUID: "00010203-0405-0607-0706-050403020100",
+ IntArray: [0x01, 0x02, 0x03],
+ String: "hello world",
+ };
+
+ hubConnection.start()
+ .then(() => {
+ return hubConnection.invoke("SendComplexObject");
+ })
+ .then((value) => {
+ if (protocol.name === "messagepack") {
+ // msgpack creates a Buffer for byte arrays and jasmine fails to compare a Buffer
+ // and a Uint8Array even though Buffer instances are also Uint8Array instances
+ value.ByteArray = new Uint8Array(value.ByteArray);
}
expect(value).toEqual(complexObject);
})
diff --git a/clients/ts/signalr-protocol-msgpack/package-lock.json b/clients/ts/signalr-protocol-msgpack/package-lock.json
index 0c622fa8e1..28f546b661 100644
--- a/clients/ts/signalr-protocol-msgpack/package-lock.json
+++ b/clients/ts/signalr-protocol-msgpack/package-lock.json
@@ -35,11 +35,12 @@
"dev": true
},
"bl": {
- "version": "1.2.1",
- "resolved": "https://registry.npmjs.org/bl/-/bl-1.2.1.tgz",
- "integrity": "sha1-ysMo977kVzDUBLaSID/LWQ4XLV4=",
+ "version": "1.2.2",
+ "resolved": "https://registry.npmjs.org/bl/-/bl-1.2.2.tgz",
+ "integrity": "sha512-e8tQYnZodmebYDWGH7KMRvtzKXaJHx3BbilrgZCfvyLUYdKpK1t5PSPmpkny/SgiTSCnjfLW7v5rlONXVFkQEA==",
"requires": {
- "readable-stream": "2.3.3"
+ "readable-stream": "2.3.6",
+ "safe-buffer": "5.1.1"
}
},
"buffer": {
@@ -74,32 +75,32 @@
"integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE="
},
"msgpack5": {
- "version": "4.0.1",
- "resolved": "https://registry.npmjs.org/msgpack5/-/msgpack5-4.0.1.tgz",
- "integrity": "sha512-Wx+c6YEE5UMrVrDQuFSIseprjgfeAvMYD35klSKm1xNCvtFI5KICfRmwKMc0Wmu7BknXUA3DUhFWugyCwTsRsg==",
+ "version": "4.0.2",
+ "resolved": "https://registry.npmjs.org/msgpack5/-/msgpack5-4.0.2.tgz",
+ "integrity": "sha512-rEIx0/KFtWGtqlF5D/NIMzOHDhm7AhIFzHR3/PLqMrXXbMKoSitDE/IDuTactlTjxEc0ScmHx/5qoH015uL7xA==",
"requires": {
- "bl": "1.2.1",
+ "bl": "1.2.2",
"inherits": "2.0.3",
- "readable-stream": "2.3.3",
+ "readable-stream": "2.3.6",
"safe-buffer": "5.1.1"
}
},
"process-nextick-args": {
- "version": "1.0.7",
- "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-1.0.7.tgz",
- "integrity": "sha1-FQ4gt1ZZCtP5EJPyWk8q2L/zC6M="
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.0.tgz",
+ "integrity": "sha512-MtEC1TqN0EU5nephaJ4rAtThHtC86dNN9qCuEhtshvpVBkAW5ZO7BASN9REnF9eoXGcRub+pFuKEpOHE+HbEMw=="
},
"readable-stream": {
- "version": "2.3.3",
- "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.3.tgz",
- "integrity": "sha512-m+qzzcn7KUxEmd1gMbchF+Y2eIUbieUaxkWtptyHywrX0rE8QEYqPC07Vuy4Wm32/xE16NcdBctb8S0Xe/5IeQ==",
+ "version": "2.3.6",
+ "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz",
+ "integrity": "sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw==",
"requires": {
"core-util-is": "1.0.2",
"inherits": "2.0.3",
"isarray": "1.0.0",
- "process-nextick-args": "1.0.7",
+ "process-nextick-args": "2.0.0",
"safe-buffer": "5.1.1",
- "string_decoder": "1.0.3",
+ "string_decoder": "1.1.1",
"util-deprecate": "1.0.2"
}
},
@@ -109,9 +110,9 @@
"integrity": "sha512-kKvNJn6Mm93gAczWVJg7wH+wGYWNrDHdWvpUmHyEsgCtIwwo3bqPtV4tR5tuPaUhTOo/kvhVwd8XwwOllGYkbg=="
},
"string_decoder": {
- "version": "1.0.3",
- "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.0.3.tgz",
- "integrity": "sha512-4AH6Z5fzNNBcH+6XDMfA/BTt87skxqJlO0lAh3Dker5zThcAxG6mKz+iGu308UKoPPQ8Dcqx/4JhujzltRa+hQ==",
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz",
+ "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==",
"requires": {
"safe-buffer": "5.1.1"
}
diff --git a/clients/ts/signalr-protocol-msgpack/package.json b/clients/ts/signalr-protocol-msgpack/package.json
index eb3347a70f..fe58caacd1 100644
--- a/clients/ts/signalr-protocol-msgpack/package.json
+++ b/clients/ts/signalr-protocol-msgpack/package.json
@@ -43,7 +43,7 @@
"@aspnet/signalr": "^1.0.0-preview3"
},
"dependencies": {
- "msgpack5": "^4.0.1"
+ "msgpack5": "^4.0.2"
},
"devDependencies": {
"@types/msgpack5": "^3.4.1",
diff --git a/samples/SignalRSamples/Startup.cs b/samples/SignalRSamples/Startup.cs
index 30de147776..2b7305f3c9 100644
--- a/samples/SignalRSamples/Startup.cs
+++ b/samples/SignalRSamples/Startup.cs
@@ -5,7 +5,6 @@ using System;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.DependencyInjection;
-using MsgPack.Serialization;
using SignalRSamples.ConnectionHandlers;
using SignalRSamples.Hubs;
@@ -24,10 +23,7 @@ namespace SignalRSamples
// Faster pings for testing
options.KeepAliveInterval = TimeSpan.FromSeconds(5);
})
- .AddMessagePackProtocol(options =>
- {
- options.SerializationContext.DictionarySerlaizationOptions.KeyTransformer = DictionaryKeyTransformers.LowerCamel;
- });
+ .AddMessagePackProtocol();
//.AddRedis();
services.AddCors(o =>
diff --git a/src/Microsoft.AspNetCore.SignalR.Protocols.MsgPack/Internal/Protocol/MessagePackHubProtocol.cs b/src/Microsoft.AspNetCore.SignalR.Protocols.MsgPack/Internal/Protocol/MessagePackHubProtocol.cs
index 18eb32ac06..8bf93d7635 100644
--- a/src/Microsoft.AspNetCore.SignalR.Protocols.MsgPack/Internal/Protocol/MessagePackHubProtocol.cs
+++ b/src/Microsoft.AspNetCore.SignalR.Protocols.MsgPack/Internal/Protocol/MessagePackHubProtocol.cs
@@ -8,12 +8,12 @@ using System.Diagnostics;
using System.IO;
using System.Runtime.ExceptionServices;
using System.Runtime.InteropServices;
+using MessagePack;
+using MessagePack.Formatters;
using Microsoft.AspNetCore.Connections;
using Microsoft.AspNetCore.Internal;
using Microsoft.AspNetCore.SignalR.Internal.Formatters;
using Microsoft.Extensions.Options;
-using MsgPack;
-using MsgPack.Serialization;
namespace Microsoft.AspNetCore.SignalR.Internal.Protocol
{
@@ -23,11 +23,11 @@ namespace Microsoft.AspNetCore.SignalR.Internal.Protocol
private const int VoidResult = 2;
private const int NonVoidResult = 3;
+ private IFormatterResolver _resolver;
+
public static readonly string ProtocolName = "messagepack";
public static readonly int ProtocolVersion = 1;
- public SerializationContext SerializationContext { get; }
-
public string Name => ProtocolName;
public int Version => ProtocolVersion;
@@ -40,7 +40,32 @@ namespace Microsoft.AspNetCore.SignalR.Internal.Protocol
public MessagePackHubProtocol(IOptions options)
{
- SerializationContext = options.Value.SerializationContext;
+ var msgPackOptions = options.Value;
+ SetupResolver(msgPackOptions);
+ }
+
+ private void SetupResolver(MessagePackHubProtocolOptions options)
+ {
+ // if counts don't match then we know users customized resolvers so we set up the options
+ // with the provided resolvers
+ if (options.FormatterResolvers.Count != SignalRResolver.Resolvers.Count)
+ {
+ _resolver = new CombinedResolvers(options.FormatterResolvers);
+ return;
+ }
+
+ for (var i = 0; i < options.FormatterResolvers.Count; i++)
+ {
+ // check if the user customized the resolvers
+ if (options.FormatterResolvers[i] != SignalRResolver.Resolvers[i])
+ {
+ _resolver = new CombinedResolvers(options.FormatterResolvers);
+ return;
+ }
+ }
+
+ // Use optimized cached resolver if the default is chosen
+ _resolver = SignalRResolver.Instance;
}
public bool IsVersionSupported(int version)
@@ -58,9 +83,8 @@ namespace Microsoft.AspNetCore.SignalR.Internal.Protocol
var arraySegment = GetArraySegment(payload);
- message = ParseMessage(arraySegment.Array, arraySegment.Offset, binder);
-
- return message != null;
+ message = ParseMessage(arraySegment.Array, arraySegment.Offset, binder, _resolver);
+ return true;
}
private static ArraySegment GetArraySegment(in ReadOnlySequence input)
@@ -77,41 +101,39 @@ namespace Microsoft.AspNetCore.SignalR.Internal.Protocol
return new ArraySegment(input.ToArray());
}
- private static HubMessage ParseMessage(byte[] input, int startOffset, IInvocationBinder binder)
+ private static HubMessage ParseMessage(byte[] input, int startOffset, IInvocationBinder binder, IFormatterResolver resolver)
{
- using (var unpacker = Unpacker.Create(input, startOffset))
+ _ = MessagePackBinary.ReadArrayHeader(input, startOffset, out var readSize);
+ startOffset += readSize;
+
+ var messageType = ReadInt32(input, ref startOffset, "messageType");
+
+ switch (messageType)
{
- _ = ReadArrayLength(unpacker, "elementCount");
-
- var messageType = ReadInt32(unpacker, "messageType");
-
- switch (messageType)
- {
- case HubProtocolConstants.InvocationMessageType:
- return CreateInvocationMessage(unpacker, binder);
- case HubProtocolConstants.StreamInvocationMessageType:
- return CreateStreamInvocationMessage(unpacker, binder);
- case HubProtocolConstants.StreamItemMessageType:
- return CreateStreamItemMessage(unpacker, binder);
- case HubProtocolConstants.CompletionMessageType:
- return CreateCompletionMessage(unpacker, binder);
- case HubProtocolConstants.CancelInvocationMessageType:
- return CreateCancelInvocationMessage(unpacker);
- case HubProtocolConstants.PingMessageType:
- return PingMessage.Instance;
- case HubProtocolConstants.CloseMessageType:
- return CreateCloseMessage(unpacker);
- default:
- // Future protocol changes can add message types, old clients can ignore them
- return null;
- }
+ case HubProtocolConstants.InvocationMessageType:
+ return CreateInvocationMessage(input, ref startOffset, binder, resolver);
+ case HubProtocolConstants.StreamInvocationMessageType:
+ return CreateStreamInvocationMessage(input, ref startOffset, binder, resolver);
+ case HubProtocolConstants.StreamItemMessageType:
+ return CreateStreamItemMessage(input, ref startOffset, binder, resolver);
+ case HubProtocolConstants.CompletionMessageType:
+ return CreateCompletionMessage(input, ref startOffset, binder, resolver);
+ case HubProtocolConstants.CancelInvocationMessageType:
+ return CreateCancelInvocationMessage(input, ref startOffset);
+ case HubProtocolConstants.PingMessageType:
+ return PingMessage.Instance;
+ case HubProtocolConstants.CloseMessageType:
+ return CreateCloseMessage(input, ref startOffset);
+ default:
+ // Future protocol changes can add message types, old clients can ignore them
+ return null;
}
}
- private static InvocationMessage CreateInvocationMessage(Unpacker unpacker, IInvocationBinder binder)
+ private static InvocationMessage CreateInvocationMessage(byte[] input, ref int offset, IInvocationBinder binder, IFormatterResolver resolver)
{
- var headers = ReadHeaders(unpacker);
- var invocationId = ReadInvocationId(unpacker);
+ var headers = ReadHeaders(input, ref offset);
+ var invocationId = ReadInvocationId(input, ref offset);
// For MsgPack, we represent an empty invocation ID as an empty string,
// so we need to normalize that to "null", which is what indicates a non-blocking invocation.
@@ -120,12 +142,12 @@ namespace Microsoft.AspNetCore.SignalR.Internal.Protocol
invocationId = null;
}
- var target = ReadString(unpacker, "target");
+ var target = ReadString(input, ref offset, "target");
var parameterTypes = binder.GetParameterTypes(target);
try
{
- var arguments = BindArguments(unpacker, parameterTypes);
+ var arguments = BindArguments(input, ref offset, parameterTypes, resolver);
return ApplyHeaders(headers, new InvocationMessage(invocationId, target, argumentBindingException: null, arguments: arguments));
}
catch (Exception ex)
@@ -134,16 +156,16 @@ namespace Microsoft.AspNetCore.SignalR.Internal.Protocol
}
}
- private static StreamInvocationMessage CreateStreamInvocationMessage(Unpacker unpacker, IInvocationBinder binder)
+ private static StreamInvocationMessage CreateStreamInvocationMessage(byte[] input, ref int offset, IInvocationBinder binder, IFormatterResolver resolver)
{
- var headers = ReadHeaders(unpacker);
- var invocationId = ReadInvocationId(unpacker);
- var target = ReadString(unpacker, "target");
+ var headers = ReadHeaders(input, ref offset);
+ var invocationId = ReadInvocationId(input, ref offset);
+ var target = ReadString(input, ref offset, "target");
var parameterTypes = binder.GetParameterTypes(target);
try
{
- var arguments = BindArguments(unpacker, parameterTypes);
+ var arguments = BindArguments(input, ref offset, parameterTypes, resolver);
return ApplyHeaders(headers, new StreamInvocationMessage(invocationId, target, argumentBindingException: null, arguments: arguments));
}
catch (Exception ex)
@@ -152,20 +174,20 @@ namespace Microsoft.AspNetCore.SignalR.Internal.Protocol
}
}
- private static StreamItemMessage CreateStreamItemMessage(Unpacker unpacker, IInvocationBinder binder)
+ private static StreamItemMessage CreateStreamItemMessage(byte[] input, ref int offset, IInvocationBinder binder, IFormatterResolver resolver)
{
- var headers = ReadHeaders(unpacker);
- var invocationId = ReadInvocationId(unpacker);
+ var headers = ReadHeaders(input, ref offset);
+ var invocationId = ReadInvocationId(input, ref offset);
var itemType = binder.GetReturnType(invocationId);
- var value = DeserializeObject(unpacker, itemType, "item");
+ var value = DeserializeObject(input, ref offset, itemType, "item", resolver);
return ApplyHeaders(headers, new StreamItemMessage(invocationId, value));
}
- private static CompletionMessage CreateCompletionMessage(Unpacker unpacker, IInvocationBinder binder)
+ private static CompletionMessage CreateCompletionMessage(byte[] input, ref int offset, IInvocationBinder binder, IFormatterResolver resolver)
{
- var headers = ReadHeaders(unpacker);
- var invocationId = ReadInvocationId(unpacker);
- var resultKind = ReadInt32(unpacker, "resultKind");
+ var headers = ReadHeaders(input, ref offset);
+ var invocationId = ReadInvocationId(input, ref offset);
+ var resultKind = ReadInt32(input, ref offset, "resultKind");
string error = null;
object result = null;
@@ -174,11 +196,11 @@ namespace Microsoft.AspNetCore.SignalR.Internal.Protocol
switch (resultKind)
{
case ErrorResult:
- error = ReadString(unpacker, "error");
+ error = ReadString(input, ref offset, "error");
break;
case NonVoidResult:
var itemType = binder.GetReturnType(invocationId);
- result = DeserializeObject(unpacker, itemType, "argument");
+ result = DeserializeObject(input, ref offset, itemType, "argument", resolver);
hasResult = true;
break;
case VoidResult:
@@ -191,22 +213,22 @@ namespace Microsoft.AspNetCore.SignalR.Internal.Protocol
return ApplyHeaders(headers, new CompletionMessage(invocationId, error, result, hasResult));
}
- private static CancelInvocationMessage CreateCancelInvocationMessage(Unpacker unpacker)
+ private static CancelInvocationMessage CreateCancelInvocationMessage(byte[] input, ref int offset)
{
- var headers = ReadHeaders(unpacker);
- var invocationId = ReadInvocationId(unpacker);
+ var headers = ReadHeaders(input, ref offset);
+ var invocationId = ReadInvocationId(input, ref offset);
return ApplyHeaders(headers, new CancelInvocationMessage(invocationId));
}
- private static CloseMessage CreateCloseMessage(Unpacker unpacker)
+ private static CloseMessage CreateCloseMessage(byte[] input, ref int offset)
{
- var error = ReadString(unpacker, "error");
+ var error = ReadString(input, ref offset, "error");
return new CloseMessage(error);
}
- private static Dictionary ReadHeaders(Unpacker unpacker)
+ private static Dictionary ReadHeaders(byte[] input, ref int offset)
{
- var headerCount = ReadMapLength(unpacker, "headers");
+ var headerCount = ReadMapLength(input, ref offset, "headers");
if (headerCount > 0)
{
// If headerCount is larger than int.MaxValue, things are going to go horribly wrong anyway :)
@@ -214,8 +236,8 @@ namespace Microsoft.AspNetCore.SignalR.Internal.Protocol
for (var i = 0; i < headerCount; i++)
{
- var key = ReadString(unpacker, $"headers[{i}].Key");
- var value = ReadString(unpacker, $"headers[{i}].Value");
+ var key = ReadString(input, ref offset, $"headers[{i}].Key");
+ var value = ReadString(input, ref offset, $"headers[{i}].Value");
headers[key] = value;
}
return headers;
@@ -226,9 +248,9 @@ namespace Microsoft.AspNetCore.SignalR.Internal.Protocol
}
}
- private static object[] BindArguments(Unpacker unpacker, IReadOnlyList parameterTypes)
+ private static object[] BindArguments(byte[] input, ref int offset, IReadOnlyList parameterTypes, IFormatterResolver resolver)
{
- var argumentCount = ReadArrayLength(unpacker, "arguments");
+ var argumentCount = ReadArrayLength(input, ref offset, "arguments");
if (parameterTypes.Count != argumentCount)
{
@@ -241,7 +263,7 @@ namespace Microsoft.AspNetCore.SignalR.Internal.Protocol
var arguments = new object[argumentCount];
for (var i = 0; i < argumentCount; i++)
{
- arguments[i] = DeserializeObject(unpacker, parameterTypes[i], "argument");
+ arguments[i] = DeserializeObject(input, ref offset, parameterTypes[i], "argument", resolver);
}
return arguments;
@@ -281,11 +303,8 @@ namespace Microsoft.AspNetCore.SignalR.Internal.Protocol
}
}
- private void WriteMessageCore(HubMessage message, Stream output)
+ private void WriteMessageCore(HubMessage message, Stream packer)
{
- // PackerCompatibilityOptions.None prevents from serializing byte[] as strings
- // and allows extended objects
- var packer = Packer.Create(output, PackerCompatibilityOptions.None);
switch (message)
{
case InvocationMessage invocationMessage:
@@ -314,135 +333,147 @@ namespace Microsoft.AspNetCore.SignalR.Internal.Protocol
}
}
- private void WriteInvocationMessage(InvocationMessage message, Packer packer)
+ private void WriteInvocationMessage(InvocationMessage message, Stream packer)
{
- packer.PackArrayHeader(5);
- packer.Pack(HubProtocolConstants.InvocationMessageType);
+ MessagePackBinary.WriteArrayHeader(packer, 5);
+ MessagePackBinary.WriteInt32(packer, HubProtocolConstants.InvocationMessageType);
PackHeaders(packer, message.Headers);
if (string.IsNullOrEmpty(message.InvocationId))
{
- packer.PackNull();
+ MessagePackBinary.WriteNil(packer);
}
else
{
- packer.PackString(message.InvocationId);
+ MessagePackBinary.WriteString(packer, message.InvocationId);
}
- packer.PackString(message.Target);
- packer.PackArrayHeader(message.Arguments.Length);
+ MessagePackBinary.WriteString(packer, message.Target);
+ MessagePackBinary.WriteArrayHeader(packer, message.Arguments.Length);
foreach (var arg in message.Arguments)
{
- packer.PackObject(arg, SerializationContext);
+ WriteArgument(arg, packer);
}
}
- private void WriteStreamInvocationMessage(StreamInvocationMessage message, Packer packer)
+ private void WriteStreamInvocationMessage(StreamInvocationMessage message, Stream packer)
{
- packer.PackArrayHeader(5);
- packer.Pack(HubProtocolConstants.StreamInvocationMessageType);
+ MessagePackBinary.WriteArrayHeader(packer, 5);
+ MessagePackBinary.WriteInt16(packer, HubProtocolConstants.StreamInvocationMessageType);
PackHeaders(packer, message.Headers);
- packer.PackString(message.InvocationId);
- packer.PackString(message.Target);
- packer.PackArrayHeader(message.Arguments.Length);
+ MessagePackBinary.WriteString(packer, message.InvocationId);
+ MessagePackBinary.WriteString(packer, message.Target);
+
+ MessagePackBinary.WriteArrayHeader(packer, message.Arguments.Length);
foreach (var arg in message.Arguments)
{
- packer.PackObject(arg, SerializationContext);
+ WriteArgument(arg, packer);
}
}
- private void WriteStreamingItemMessage(StreamItemMessage message, Packer packer)
+ private void WriteStreamingItemMessage(StreamItemMessage message, Stream packer)
{
- packer.PackArrayHeader(4);
- packer.Pack(HubProtocolConstants.StreamItemMessageType);
+ MessagePackBinary.WriteArrayHeader(packer, 4);
+ MessagePackBinary.WriteInt16(packer, HubProtocolConstants.StreamItemMessageType);
PackHeaders(packer, message.Headers);
- packer.PackString(message.InvocationId);
- packer.PackObject(message.Item, SerializationContext);
+ MessagePackBinary.WriteString(packer, message.InvocationId);
+ WriteArgument(message.Item, packer);
}
- private void WriteCompletionMessage(CompletionMessage message, Packer packer)
+ private void WriteArgument(object argument, Stream stream)
+ {
+ if (argument == null)
+ {
+ MessagePackBinary.WriteNil(stream);
+ }
+ else
+ {
+ MessagePackSerializer.NonGeneric.Serialize(argument.GetType(), stream, argument, _resolver);
+ }
+ }
+
+ private void WriteCompletionMessage(CompletionMessage message, Stream packer)
{
var resultKind =
message.Error != null ? ErrorResult :
message.HasResult ? NonVoidResult :
VoidResult;
- packer.PackArrayHeader(4 + (resultKind != VoidResult ? 1 : 0));
- packer.Pack(HubProtocolConstants.CompletionMessageType);
+ MessagePackBinary.WriteArrayHeader(packer, 4 + (resultKind != VoidResult ? 1 : 0));
+ MessagePackBinary.WriteInt32(packer, HubProtocolConstants.CompletionMessageType);
PackHeaders(packer, message.Headers);
- packer.PackString(message.InvocationId);
- packer.Pack(resultKind);
+ MessagePackBinary.WriteString(packer, message.InvocationId);
+ MessagePackBinary.WriteInt32(packer, resultKind);
switch (resultKind)
{
case ErrorResult:
- packer.PackString(message.Error);
+ MessagePackBinary.WriteString(packer, message.Error);
break;
case NonVoidResult:
- packer.PackObject(message.Result, SerializationContext);
+ WriteArgument(message.Result, packer);
break;
}
}
- private void WriteCancelInvocationMessage(CancelInvocationMessage message, Packer packer)
+ private void WriteCancelInvocationMessage(CancelInvocationMessage message, Stream packer)
{
- packer.PackArrayHeader(3);
- packer.Pack(HubProtocolConstants.CancelInvocationMessageType);
+ MessagePackBinary.WriteArrayHeader(packer, 3);
+ MessagePackBinary.WriteInt16(packer, HubProtocolConstants.CancelInvocationMessageType);
PackHeaders(packer, message.Headers);
- packer.PackString(message.InvocationId);
+ MessagePackBinary.WriteString(packer, message.InvocationId);
}
- private void WriteCloseMessage(CloseMessage message, Packer packer)
+ private void WriteCloseMessage(CloseMessage message, Stream packer)
{
- packer.PackArrayHeader(2);
- packer.Pack(HubProtocolConstants.CloseMessageType);
+ MessagePackBinary.WriteArrayHeader(packer, 2);
+ MessagePackBinary.WriteInt16(packer, HubProtocolConstants.CloseMessageType);
if (string.IsNullOrEmpty(message.Error))
{
- packer.PackNull();
+ MessagePackBinary.WriteNil(packer);
}
else
{
- packer.PackString(message.Error);
+ MessagePackBinary.WriteString(packer, message.Error);
}
}
- private void WritePingMessage(PingMessage pingMessage, Packer packer)
+ private void WritePingMessage(PingMessage pingMessage, Stream packer)
{
- packer.PackArrayHeader(1);
- packer.Pack(HubProtocolConstants.PingMessageType);
+ MessagePackBinary.WriteArrayHeader(packer, 1);
+ MessagePackBinary.WriteInt32(packer, HubProtocolConstants.PingMessageType);
}
- private void PackHeaders(Packer packer, IDictionary headers)
+ private void PackHeaders(Stream packer, IDictionary headers)
{
if (headers != null)
{
- packer.PackMapHeader(headers.Count);
+ MessagePackBinary.WriteMapHeader(packer, headers.Count);
if (headers.Count > 0)
{
foreach (var header in headers)
{
- packer.PackString(header.Key);
- packer.PackString(header.Value);
+ MessagePackBinary.WriteString(packer, header.Key);
+ MessagePackBinary.WriteString(packer, header.Value);
}
}
}
else
{
- packer.PackMapHeader(0);
+ MessagePackBinary.WriteMapHeader(packer, 0);
}
}
- private static string ReadInvocationId(Unpacker unpacker)
+ private static string ReadInvocationId(byte[] input, ref int offset)
{
- return ReadString(unpacker, "invocationId");
+ return ReadString(input, ref offset, "invocationId");
}
- private static int ReadInt32(Unpacker unpacker, string field)
+ private static int ReadInt32(byte[] input, ref int offset, string field)
{
Exception msgPackException = null;
try
{
- if (unpacker.ReadInt32(out var value))
- {
- return value;
- }
+ var readInt = MessagePackBinary.ReadInt32(input, offset, out var readSize);
+ offset += readSize;
+ return readInt;
}
catch (Exception e)
{
@@ -452,22 +483,14 @@ namespace Microsoft.AspNetCore.SignalR.Internal.Protocol
throw new InvalidDataException($"Reading '{field}' as Int32 failed.", msgPackException);
}
- private static string ReadString(Unpacker unpacker, string field)
+ private static string ReadString(byte[] input, ref int offset, string field)
{
Exception msgPackException = null;
try
{
- if (unpacker.Read())
- {
- if (unpacker.LastReadData.IsNil)
- {
- return null;
- }
- else
- {
- return unpacker.LastReadData.AsString();
- }
- }
+ var readString = MessagePackBinary.ReadString(input, offset, out var readSize);
+ offset += readSize;
+ return readString;
}
catch (Exception e)
{
@@ -477,15 +500,14 @@ namespace Microsoft.AspNetCore.SignalR.Internal.Protocol
throw new InvalidDataException($"Reading '{field}' as String failed.", msgPackException);
}
- private static bool ReadBoolean(Unpacker unpacker, string field)
+ private static bool ReadBoolean(byte[] input, ref int offset, string field)
{
Exception msgPackException = null;
try
{
- if (unpacker.ReadBoolean(out var value))
- {
- return value;
- }
+ var readBool = MessagePackBinary.ReadBoolean(input, offset, out var readSize);
+ offset += readSize;
+ return readBool;
}
catch (Exception e)
{
@@ -495,15 +517,14 @@ namespace Microsoft.AspNetCore.SignalR.Internal.Protocol
throw new InvalidDataException($"Reading '{field}' as Boolean failed.", msgPackException);
}
- private static long ReadMapLength(Unpacker unpacker, string field)
+ private static long ReadMapLength(byte[] input, ref int offset, string field)
{
Exception msgPackException = null;
try
{
- if (unpacker.ReadMapLength(out var value))
- {
- return value;
- }
+ var readMap = MessagePackBinary.ReadMapHeader(input, offset, out var readSize);
+ offset += readSize;
+ return readMap;
}
catch (Exception e)
{
@@ -513,15 +534,14 @@ namespace Microsoft.AspNetCore.SignalR.Internal.Protocol
throw new InvalidDataException($"Reading map length for '{field}' failed.", msgPackException);
}
- private static long ReadArrayLength(Unpacker unpacker, string field)
+ private static long ReadArrayLength(byte[] input, ref int offset, string field)
{
Exception msgPackException = null;
try
{
- if (unpacker.ReadArrayLength(out var value))
- {
- return value;
- }
+ var readArray = MessagePackBinary.ReadArrayHeader(input, offset, out var readSize);
+ offset += readSize;
+ return readArray;
}
catch (Exception e)
{
@@ -531,16 +551,14 @@ namespace Microsoft.AspNetCore.SignalR.Internal.Protocol
throw new InvalidDataException($"Reading array length for '{field}' failed.", msgPackException);
}
- private static object DeserializeObject(Unpacker unpacker, Type type, string field)
+ private static object DeserializeObject(byte[] input, ref int offset, Type type, string field, IFormatterResolver resolver)
{
Exception msgPackException = null;
try
{
- if (unpacker.Read())
- {
- var serializer = MessagePackSerializer.Get(type);
- return serializer.UnpackFrom(unpacker);
- }
+ var obj = MessagePackSerializer.NonGeneric.Deserialize(type, new ArraySegment(input, offset, input.Length - offset), resolver);
+ offset += MessagePackBinary.ReadNextBlock(input, offset);
+ return obj;
}
catch (Exception ex)
{
@@ -550,14 +568,68 @@ namespace Microsoft.AspNetCore.SignalR.Internal.Protocol
throw new InvalidDataException($"Deserializing object of the `{type.Name}` type for '{field}' failed.", msgPackException);
}
- internal static SerializationContext CreateDefaultSerializationContext()
+ internal static List CreateDefaultFormatterResolvers()
{
- // serializes objects (here: arguments and results) as maps so that property names are preserved
- var serializationContext = new SerializationContext { SerializationMethod = SerializationMethod.Map };
+ // Copy to allow users to add/remove resolvers without changing the static SignalRResolver list
+ return new List(SignalRResolver.Resolvers);
+ }
- // allows for serializing objects that cannot be deserialized due to the lack of the default ctor etc.
- serializationContext.CompatibilityOptions.AllowAsymmetricSerializer = true;
- return serializationContext;
+ internal class SignalRResolver : IFormatterResolver
+ {
+ public static readonly IFormatterResolver Instance = new SignalRResolver();
+
+ public static readonly IList Resolvers = new[]
+ {
+ MessagePack.Resolvers.DynamicEnumAsStringResolver.Instance,
+ MessagePack.Resolvers.ContractlessStandardResolver.Instance,
+ };
+
+ public IMessagePackFormatter GetFormatter()
+ {
+ return Cache.Formatter;
+ }
+
+ private static class Cache
+ {
+ public static readonly IMessagePackFormatter Formatter;
+
+ static Cache()
+ {
+ foreach (var resolver in Resolvers)
+ {
+ Formatter = resolver.GetFormatter();
+ if (Formatter != null)
+ {
+ return;
+ }
+ }
+ }
+ }
+ }
+
+ // Support for users making their own Formatter lists
+ internal class CombinedResolvers : IFormatterResolver
+ {
+ private readonly IList _resolvers;
+
+ public CombinedResolvers(IList resolvers)
+ {
+ _resolvers = resolvers;
+ }
+
+ public IMessagePackFormatter GetFormatter()
+ {
+ foreach (var resolver in _resolvers)
+ {
+ var formatter = resolver.GetFormatter();
+ if (formatter != null)
+ {
+ return formatter;
+ }
+ }
+
+ return null;
+ }
}
}
}
diff --git a/src/Microsoft.AspNetCore.SignalR.Protocols.MsgPack/MessagePackHubProtocolOptions.cs b/src/Microsoft.AspNetCore.SignalR.Protocols.MsgPack/MessagePackHubProtocolOptions.cs
index de417ac1e1..cd4d509a9a 100644
--- a/src/Microsoft.AspNetCore.SignalR.Protocols.MsgPack/MessagePackHubProtocolOptions.cs
+++ b/src/Microsoft.AspNetCore.SignalR.Protocols.MsgPack/MessagePackHubProtocolOptions.cs
@@ -1,13 +1,14 @@
// 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 System.Collections.Generic;
+using MessagePack;
using Microsoft.AspNetCore.SignalR.Internal.Protocol;
-using MsgPack.Serialization;
namespace Microsoft.AspNetCore.SignalR
{
public class MessagePackHubProtocolOptions
{
- public SerializationContext SerializationContext { get; set; } = MessagePackHubProtocol.CreateDefaultSerializationContext();
+ public IList FormatterResolvers { get; set; } = MessagePackHubProtocol.CreateDefaultFormatterResolvers();
}
}
diff --git a/src/Microsoft.AspNetCore.SignalR.Protocols.MsgPack/Microsoft.AspNetCore.SignalR.Protocols.MsgPack.csproj b/src/Microsoft.AspNetCore.SignalR.Protocols.MsgPack/Microsoft.AspNetCore.SignalR.Protocols.MsgPack.csproj
index 1fb060bc20..a4c7cbc0be 100644
--- a/src/Microsoft.AspNetCore.SignalR.Protocols.MsgPack/Microsoft.AspNetCore.SignalR.Protocols.MsgPack.csproj
+++ b/src/Microsoft.AspNetCore.SignalR.Protocols.MsgPack/Microsoft.AspNetCore.SignalR.Protocols.MsgPack.csproj
@@ -12,7 +12,7 @@
-
+
diff --git a/test/Microsoft.AspNetCore.SignalR.Client.Tests/HubConnectionBuilderTests.cs b/test/Microsoft.AspNetCore.SignalR.Client.Tests/HubConnectionBuilderTests.cs
index fbb1216c96..25187f61a0 100644
--- a/test/Microsoft.AspNetCore.SignalR.Client.Tests/HubConnectionBuilderTests.cs
+++ b/test/Microsoft.AspNetCore.SignalR.Client.Tests/HubConnectionBuilderTests.cs
@@ -7,7 +7,6 @@ using System.Threading.Tasks;
using Microsoft.AspNetCore.Connections;
using Microsoft.AspNetCore.SignalR.Internal.Protocol;
using Microsoft.Extensions.DependencyInjection;
-using MsgPack.Serialization;
using Newtonsoft.Json;
using Newtonsoft.Json.Serialization;
using Xunit;
@@ -78,27 +77,11 @@ namespace Microsoft.AspNetCore.SignalR.Client.Tests
}
[Fact]
- public void AddMessagePackProtocolSetsHubProtocolToMsgPackWithDefaultOptions()
+ public void AddMessagePackProtocolSetsHubProtocolToMsgPack()
{
var serviceProvider = new HubConnectionBuilder().AddMessagePackProtocol().Services.BuildServiceProvider();
- var actualProtocol = Assert.IsType(serviceProvider.GetService());
- Assert.Equal(SerializationMethod.Map, actualProtocol.SerializationContext.SerializationMethod);
- }
-
- [Fact]
- public void AddMessagePackProtocolSetsHubProtocolToMsgPackWithProvidedOptions()
- {
- var serviceProvider = new HubConnectionBuilder().AddMessagePackProtocol(options =>
- {
- options.SerializationContext = new SerializationContext
- {
- SerializationMethod = SerializationMethod.Array
- };
- }).Services.BuildServiceProvider();
-
- var actualProtocol = Assert.IsType(serviceProvider.GetService());
- Assert.Equal(SerializationMethod.Array, actualProtocol.SerializationContext.SerializationMethod);
+ Assert.IsType(serviceProvider.GetService());
}
}
}
diff --git a/test/Microsoft.AspNetCore.SignalR.Common.Tests/Internal/Protocol/CustomObject.cs b/test/Microsoft.AspNetCore.SignalR.Common.Tests/Internal/Protocol/CustomObject.cs
index 123267d45d..fbc84022a1 100644
--- a/test/Microsoft.AspNetCore.SignalR.Common.Tests/Internal/Protocol/CustomObject.cs
+++ b/test/Microsoft.AspNetCore.SignalR.Common.Tests/Internal/Protocol/CustomObject.cs
@@ -14,7 +14,7 @@ namespace Microsoft.AspNetCore.SignalR.Common.Tests.Internal.Protocol
public int IntProp { get; set; } = 42;
- public DateTime DateTimeProp { get; set; } = new DateTime(2017, 4, 11);
+ public DateTime DateTimeProp { get; set; } = new DateTime(2017, 4, 11, 0, 0, 0, DateTimeKind.Utc);
public object NullProp { get; set; } = null;
diff --git a/test/Microsoft.AspNetCore.SignalR.Common.Tests/Internal/Protocol/JsonHubProtocolTests.cs b/test/Microsoft.AspNetCore.SignalR.Common.Tests/Internal/Protocol/JsonHubProtocolTests.cs
index b8e7018298..81d72e7c3b 100644
--- a/test/Microsoft.AspNetCore.SignalR.Common.Tests/Internal/Protocol/JsonHubProtocolTests.cs
+++ b/test/Microsoft.AspNetCore.SignalR.Common.Tests/Internal/Protocol/JsonHubProtocolTests.cs
@@ -37,10 +37,10 @@ namespace Microsoft.AspNetCore.SignalR.Common.Tests.Internal.Protocol
new JsonProtocolTestData("InvocationMessage_HasFloatArgument", new InvocationMessage(null, "Target", null, 1, "Foo", 2.0f), true, NullValueHandling.Ignore, "{\"type\":1,\"target\":\"Target\",\"arguments\":[1,\"Foo\",2.0]}"),
new JsonProtocolTestData("InvocationMessage_HasBoolArgument", new InvocationMessage(null, "Target", null, true), true, NullValueHandling.Ignore, "{\"type\":1,\"target\":\"Target\",\"arguments\":[true]}"),
new JsonProtocolTestData("InvocationMessage_HasNullArgument", new InvocationMessage(null, "Target", null, new object[] { null }), true, NullValueHandling.Ignore, "{\"type\":1,\"target\":\"Target\",\"arguments\":[null]}"),
- new JsonProtocolTestData("InvocationMessage_HasCustomArgumentWithNoCamelCase", new InvocationMessage(null, "Target", null, new CustomObject()), false, NullValueHandling.Ignore, "{\"type\":1,\"target\":\"Target\",\"arguments\":[{\"StringProp\":\"SignalR!\",\"DoubleProp\":6.2831853071,\"IntProp\":42,\"DateTimeProp\":\"2017-04-11T00:00:00\",\"ByteArrProp\":\"AQID\"}]}"),
- new JsonProtocolTestData("InvocationMessage_HasCustomArgumentWithNullValueIgnore", new InvocationMessage(null, "Target", null, new CustomObject()), true, NullValueHandling.Ignore, "{\"type\":1,\"target\":\"Target\",\"arguments\":[{\"stringProp\":\"SignalR!\",\"doubleProp\":6.2831853071,\"intProp\":42,\"dateTimeProp\":\"2017-04-11T00:00:00\",\"byteArrProp\":\"AQID\"}]}"),
- new JsonProtocolTestData("InvocationMessage_HasCustomArgumentWithNullValueIgnoreAndNoCamelCase", new InvocationMessage(null, "Target", null, new CustomObject()), false, NullValueHandling.Include, "{\"type\":1,\"target\":\"Target\",\"arguments\":[{\"StringProp\":\"SignalR!\",\"DoubleProp\":6.2831853071,\"IntProp\":42,\"DateTimeProp\":\"2017-04-11T00:00:00\",\"NullProp\":null,\"ByteArrProp\":\"AQID\"}]}"),
- new JsonProtocolTestData("InvocationMessage_HasCustomArgumentWithNullValueInclude", new InvocationMessage(null, "Target", null, new CustomObject()), true, NullValueHandling.Include, "{\"type\":1,\"target\":\"Target\",\"arguments\":[{\"stringProp\":\"SignalR!\",\"doubleProp\":6.2831853071,\"intProp\":42,\"dateTimeProp\":\"2017-04-11T00:00:00\",\"nullProp\":null,\"byteArrProp\":\"AQID\"}]}"),
+ new JsonProtocolTestData("InvocationMessage_HasCustomArgumentWithNoCamelCase", new InvocationMessage(null, "Target", null, new CustomObject()), false, NullValueHandling.Ignore, "{\"type\":1,\"target\":\"Target\",\"arguments\":[{\"StringProp\":\"SignalR!\",\"DoubleProp\":6.2831853071,\"IntProp\":42,\"DateTimeProp\":\"2017-04-11T00:00:00Z\",\"ByteArrProp\":\"AQID\"}]}"),
+ new JsonProtocolTestData("InvocationMessage_HasCustomArgumentWithNullValueIgnore", new InvocationMessage(null, "Target", null, new CustomObject()), true, NullValueHandling.Ignore, "{\"type\":1,\"target\":\"Target\",\"arguments\":[{\"stringProp\":\"SignalR!\",\"doubleProp\":6.2831853071,\"intProp\":42,\"dateTimeProp\":\"2017-04-11T00:00:00Z\",\"byteArrProp\":\"AQID\"}]}"),
+ new JsonProtocolTestData("InvocationMessage_HasCustomArgumentWithNullValueIgnoreAndNoCamelCase", new InvocationMessage(null, "Target", null, new CustomObject()), false, NullValueHandling.Include, "{\"type\":1,\"target\":\"Target\",\"arguments\":[{\"StringProp\":\"SignalR!\",\"DoubleProp\":6.2831853071,\"IntProp\":42,\"DateTimeProp\":\"2017-04-11T00:00:00Z\",\"NullProp\":null,\"ByteArrProp\":\"AQID\"}]}"),
+ new JsonProtocolTestData("InvocationMessage_HasCustomArgumentWithNullValueInclude", new InvocationMessage(null, "Target", null, new CustomObject()), true, NullValueHandling.Include, "{\"type\":1,\"target\":\"Target\",\"arguments\":[{\"stringProp\":\"SignalR!\",\"doubleProp\":6.2831853071,\"intProp\":42,\"dateTimeProp\":\"2017-04-11T00:00:00Z\",\"nullProp\":null,\"byteArrProp\":\"AQID\"}]}"),
new JsonProtocolTestData("InvocationMessage_HasHeaders", AddHeaders(TestHeaders, new InvocationMessage("123", "Target", null, 1, "Foo", 2.0f)), true, NullValueHandling.Ignore, "{\"type\":1," + SerializedHeaders + ",\"invocationId\":\"123\",\"target\":\"Target\",\"arguments\":[1,\"Foo\",2.0]}"),
new JsonProtocolTestData("InvocationMessage_StringIsoDateArgument", new InvocationMessage("Method", null, "2016-05-10T13:51:20+12:34"), true, NullValueHandling.Ignore, "{\"type\":1,\"target\":\"Method\",\"arguments\":[\"2016-05-10T13:51:20+12:34\"]}"),
new JsonProtocolTestData("InvocationMessage_DateTimeOffsetArgument", new InvocationMessage("Method", null, DateTimeOffset.Parse("2016-05-10T13:51:20+12:34")), true, NullValueHandling.Ignore, "{\"type\":1,\"target\":\"Method\",\"arguments\":[\"2016-05-10T13:51:20+12:34\"]}"),
@@ -50,22 +50,22 @@ namespace Microsoft.AspNetCore.SignalR.Common.Tests.Internal.Protocol
new JsonProtocolTestData("StreamItemMessage_HasFloatItem", new StreamItemMessage("123", 2.0f), true, NullValueHandling.Ignore, "{\"type\":2,\"invocationId\":\"123\",\"item\":2.0}"),
new JsonProtocolTestData("StreamItemMessage_HasBoolItem", new StreamItemMessage("123", true), true, NullValueHandling.Ignore, "{\"type\":2,\"invocationId\":\"123\",\"item\":true}"),
new JsonProtocolTestData("StreamItemMessage_HasNullItem", new StreamItemMessage("123", null), true, NullValueHandling.Ignore, "{\"type\":2,\"invocationId\":\"123\",\"item\":null}"),
- new JsonProtocolTestData("StreamItemMessage_HasCustomItemWithNoCamelCase", new StreamItemMessage("123", new CustomObject()), false, NullValueHandling.Ignore, "{\"type\":2,\"invocationId\":\"123\",\"item\":{\"StringProp\":\"SignalR!\",\"DoubleProp\":6.2831853071,\"IntProp\":42,\"DateTimeProp\":\"2017-04-11T00:00:00\",\"ByteArrProp\":\"AQID\"}}"),
- new JsonProtocolTestData("StreamItemMessage_HasCustomItemWithNullValueIgnore", new StreamItemMessage("123", new CustomObject()), true, NullValueHandling.Ignore, "{\"type\":2,\"invocationId\":\"123\",\"item\":{\"stringProp\":\"SignalR!\",\"doubleProp\":6.2831853071,\"intProp\":42,\"dateTimeProp\":\"2017-04-11T00:00:00\",\"byteArrProp\":\"AQID\"}}"),
- new JsonProtocolTestData("StreamItemMessage_HasCustomItemWithNullValueIgnoreAndNoCamelCase", new StreamItemMessage("123", new CustomObject()), false, NullValueHandling.Include, "{\"type\":2,\"invocationId\":\"123\",\"item\":{\"StringProp\":\"SignalR!\",\"DoubleProp\":6.2831853071,\"IntProp\":42,\"DateTimeProp\":\"2017-04-11T00:00:00\",\"NullProp\":null,\"ByteArrProp\":\"AQID\"}}"),
- new JsonProtocolTestData("StreamItemMessage_HasCustomItemWithNullValueInclude", new StreamItemMessage("123", new CustomObject()), true, NullValueHandling.Include, "{\"type\":2,\"invocationId\":\"123\",\"item\":{\"stringProp\":\"SignalR!\",\"doubleProp\":6.2831853071,\"intProp\":42,\"dateTimeProp\":\"2017-04-11T00:00:00\",\"nullProp\":null,\"byteArrProp\":\"AQID\"}}"),
- new JsonProtocolTestData("StreamItemMessage_HasHeaders", AddHeaders(TestHeaders, new StreamItemMessage("123", new CustomObject())), true, NullValueHandling.Include, "{\"type\":2," + SerializedHeaders + ",\"invocationId\":\"123\",\"item\":{\"stringProp\":\"SignalR!\",\"doubleProp\":6.2831853071,\"intProp\":42,\"dateTimeProp\":\"2017-04-11T00:00:00\",\"nullProp\":null,\"byteArrProp\":\"AQID\"}}"),
+ new JsonProtocolTestData("StreamItemMessage_HasCustomItemWithNoCamelCase", new StreamItemMessage("123", new CustomObject()), false, NullValueHandling.Ignore, "{\"type\":2,\"invocationId\":\"123\",\"item\":{\"StringProp\":\"SignalR!\",\"DoubleProp\":6.2831853071,\"IntProp\":42,\"DateTimeProp\":\"2017-04-11T00:00:00Z\",\"ByteArrProp\":\"AQID\"}}"),
+ new JsonProtocolTestData("StreamItemMessage_HasCustomItemWithNullValueIgnore", new StreamItemMessage("123", new CustomObject()), true, NullValueHandling.Ignore, "{\"type\":2,\"invocationId\":\"123\",\"item\":{\"stringProp\":\"SignalR!\",\"doubleProp\":6.2831853071,\"intProp\":42,\"dateTimeProp\":\"2017-04-11T00:00:00Z\",\"byteArrProp\":\"AQID\"}}"),
+ new JsonProtocolTestData("StreamItemMessage_HasCustomItemWithNullValueIgnoreAndNoCamelCase", new StreamItemMessage("123", new CustomObject()), false, NullValueHandling.Include, "{\"type\":2,\"invocationId\":\"123\",\"item\":{\"StringProp\":\"SignalR!\",\"DoubleProp\":6.2831853071,\"IntProp\":42,\"DateTimeProp\":\"2017-04-11T00:00:00Z\",\"NullProp\":null,\"ByteArrProp\":\"AQID\"}}"),
+ new JsonProtocolTestData("StreamItemMessage_HasCustomItemWithNullValueInclude", new StreamItemMessage("123", new CustomObject()), true, NullValueHandling.Include, "{\"type\":2,\"invocationId\":\"123\",\"item\":{\"stringProp\":\"SignalR!\",\"doubleProp\":6.2831853071,\"intProp\":42,\"dateTimeProp\":\"2017-04-11T00:00:00Z\",\"nullProp\":null,\"byteArrProp\":\"AQID\"}}"),
+ new JsonProtocolTestData("StreamItemMessage_HasHeaders", AddHeaders(TestHeaders, new StreamItemMessage("123", new CustomObject())), true, NullValueHandling.Include, "{\"type\":2," + SerializedHeaders + ",\"invocationId\":\"123\",\"item\":{\"stringProp\":\"SignalR!\",\"doubleProp\":6.2831853071,\"intProp\":42,\"dateTimeProp\":\"2017-04-11T00:00:00Z\",\"nullProp\":null,\"byteArrProp\":\"AQID\"}}"),
new JsonProtocolTestData("CompletionMessage_HasIntergerResult", CompletionMessage.WithResult("123", 1), true, NullValueHandling.Ignore, "{\"type\":3,\"invocationId\":\"123\",\"result\":1}"),
new JsonProtocolTestData("CompletionMessage_HasStringResult", CompletionMessage.WithResult("123", "Foo"), true, NullValueHandling.Ignore, "{\"type\":3,\"invocationId\":\"123\",\"result\":\"Foo\"}"),
new JsonProtocolTestData("CompletionMessage_HasFloatResult", CompletionMessage.WithResult("123", 2.0f), true, NullValueHandling.Ignore, "{\"type\":3,\"invocationId\":\"123\",\"result\":2.0}"),
new JsonProtocolTestData("CompletionMessage_HasBoolResult", CompletionMessage.WithResult("123", true), true, NullValueHandling.Ignore, "{\"type\":3,\"invocationId\":\"123\",\"result\":true}"),
new JsonProtocolTestData("CompletionMessage_HasNullResult", CompletionMessage.WithResult("123", null), true, NullValueHandling.Ignore, "{\"type\":3,\"invocationId\":\"123\",\"result\":null}"),
- new JsonProtocolTestData("CompletionMessage_HasCustomResultWithNoCamelCase", CompletionMessage.WithResult("123", new CustomObject()), false, NullValueHandling.Ignore, "{\"type\":3,\"invocationId\":\"123\",\"result\":{\"StringProp\":\"SignalR!\",\"DoubleProp\":6.2831853071,\"IntProp\":42,\"DateTimeProp\":\"2017-04-11T00:00:00\",\"ByteArrProp\":\"AQID\"}}"),
- new JsonProtocolTestData("CompletionMessage_HasCustomResultWithNullValueIgnore", CompletionMessage.WithResult("123", new CustomObject()), true, NullValueHandling.Ignore, "{\"type\":3,\"invocationId\":\"123\",\"result\":{\"stringProp\":\"SignalR!\",\"doubleProp\":6.2831853071,\"intProp\":42,\"dateTimeProp\":\"2017-04-11T00:00:00\",\"byteArrProp\":\"AQID\"}}"),
- new JsonProtocolTestData("CompletionMessage_HasCustomResultWithNullValueIncludeAndNoCamelCase", CompletionMessage.WithResult("123", new CustomObject()), false, NullValueHandling.Include, "{\"type\":3,\"invocationId\":\"123\",\"result\":{\"StringProp\":\"SignalR!\",\"DoubleProp\":6.2831853071,\"IntProp\":42,\"DateTimeProp\":\"2017-04-11T00:00:00\",\"NullProp\":null,\"ByteArrProp\":\"AQID\"}}"),
- new JsonProtocolTestData("CompletionMessage_HasCustomResultWithNullValueInclude", CompletionMessage.WithResult("123", new CustomObject()), true, NullValueHandling.Include, "{\"type\":3,\"invocationId\":\"123\",\"result\":{\"stringProp\":\"SignalR!\",\"doubleProp\":6.2831853071,\"intProp\":42,\"dateTimeProp\":\"2017-04-11T00:00:00\",\"nullProp\":null,\"byteArrProp\":\"AQID\"}}"),
- new JsonProtocolTestData("CompletionMessage_HasTestHeadersAndCustomItemResult", AddHeaders(TestHeaders, CompletionMessage.WithResult("123", new CustomObject())), true, NullValueHandling.Include, "{\"type\":3," + SerializedHeaders + ",\"invocationId\":\"123\",\"result\":{\"stringProp\":\"SignalR!\",\"doubleProp\":6.2831853071,\"intProp\":42,\"dateTimeProp\":\"2017-04-11T00:00:00\",\"nullProp\":null,\"byteArrProp\":\"AQID\"}}"),
+ new JsonProtocolTestData("CompletionMessage_HasCustomResultWithNoCamelCase", CompletionMessage.WithResult("123", new CustomObject()), false, NullValueHandling.Ignore, "{\"type\":3,\"invocationId\":\"123\",\"result\":{\"StringProp\":\"SignalR!\",\"DoubleProp\":6.2831853071,\"IntProp\":42,\"DateTimeProp\":\"2017-04-11T00:00:00Z\",\"ByteArrProp\":\"AQID\"}}"),
+ new JsonProtocolTestData("CompletionMessage_HasCustomResultWithNullValueIgnore", CompletionMessage.WithResult("123", new CustomObject()), true, NullValueHandling.Ignore, "{\"type\":3,\"invocationId\":\"123\",\"result\":{\"stringProp\":\"SignalR!\",\"doubleProp\":6.2831853071,\"intProp\":42,\"dateTimeProp\":\"2017-04-11T00:00:00Z\",\"byteArrProp\":\"AQID\"}}"),
+ new JsonProtocolTestData("CompletionMessage_HasCustomResultWithNullValueIncludeAndNoCamelCase", CompletionMessage.WithResult("123", new CustomObject()), false, NullValueHandling.Include, "{\"type\":3,\"invocationId\":\"123\",\"result\":{\"StringProp\":\"SignalR!\",\"DoubleProp\":6.2831853071,\"IntProp\":42,\"DateTimeProp\":\"2017-04-11T00:00:00Z\",\"NullProp\":null,\"ByteArrProp\":\"AQID\"}}"),
+ new JsonProtocolTestData("CompletionMessage_HasCustomResultWithNullValueInclude", CompletionMessage.WithResult("123", new CustomObject()), true, NullValueHandling.Include, "{\"type\":3,\"invocationId\":\"123\",\"result\":{\"stringProp\":\"SignalR!\",\"doubleProp\":6.2831853071,\"intProp\":42,\"dateTimeProp\":\"2017-04-11T00:00:00Z\",\"nullProp\":null,\"byteArrProp\":\"AQID\"}}"),
+ new JsonProtocolTestData("CompletionMessage_HasTestHeadersAndCustomItemResult", AddHeaders(TestHeaders, CompletionMessage.WithResult("123", new CustomObject())), true, NullValueHandling.Include, "{\"type\":3," + SerializedHeaders + ",\"invocationId\":\"123\",\"result\":{\"stringProp\":\"SignalR!\",\"doubleProp\":6.2831853071,\"intProp\":42,\"dateTimeProp\":\"2017-04-11T00:00:00Z\",\"nullProp\":null,\"byteArrProp\":\"AQID\"}}"),
new JsonProtocolTestData("CompletionMessage_HasError", CompletionMessage.WithError("123", "Whoops!"), false, NullValueHandling.Ignore, "{\"type\":3,\"invocationId\":\"123\",\"error\":\"Whoops!\"}"),
new JsonProtocolTestData("CompletionMessage_HasErrorAndHeaders", AddHeaders(TestHeaders, CompletionMessage.WithError("123", "Whoops!")), false, NullValueHandling.Ignore, "{\"type\":3," + SerializedHeaders + ",\"invocationId\":\"123\",\"error\":\"Whoops!\"}"),
new JsonProtocolTestData("CompletionMessage_HasErrorAndCamelCase", CompletionMessage.Empty("123"), true, NullValueHandling.Ignore, "{\"type\":3,\"invocationId\":\"123\"}"),
@@ -75,11 +75,11 @@ namespace Microsoft.AspNetCore.SignalR.Common.Tests.Internal.Protocol
new JsonProtocolTestData("StreamInvocationMessage_HasFloatArgument", new StreamInvocationMessage("123", "Target", null, 1, "Foo", 2.0f), true, NullValueHandling.Ignore, "{\"type\":4,\"invocationId\":\"123\",\"target\":\"Target\",\"arguments\":[1,\"Foo\",2.0]}"),
new JsonProtocolTestData("StreamInvocationMessage_HasBoolArgument", new StreamInvocationMessage("123", "Target", null, true), true, NullValueHandling.Ignore, "{\"type\":4,\"invocationId\":\"123\",\"target\":\"Target\",\"arguments\":[true]}"),
new JsonProtocolTestData("StreamInvocationMessage_HasNullArgument", new StreamInvocationMessage("123", "Target", null, new object[] { null }), true, NullValueHandling.Ignore, "{\"type\":4,\"invocationId\":\"123\",\"target\":\"Target\",\"arguments\":[null]}"),
- new JsonProtocolTestData("StreamInvocationMessage_HasCustomArgumentWithNoCamelCase", new StreamInvocationMessage("123", "Target", null, new CustomObject()), false, NullValueHandling.Ignore, "{\"type\":4,\"invocationId\":\"123\",\"target\":\"Target\",\"arguments\":[{\"StringProp\":\"SignalR!\",\"DoubleProp\":6.2831853071,\"IntProp\":42,\"DateTimeProp\":\"2017-04-11T00:00:00\",\"ByteArrProp\":\"AQID\"}]}"),
- new JsonProtocolTestData("StreamInvocationMessage_HasCustomArgumentWithNullValueIgnore", new StreamInvocationMessage("123", "Target", null, new CustomObject()), true, NullValueHandling.Ignore, "{\"type\":4,\"invocationId\":\"123\",\"target\":\"Target\",\"arguments\":[{\"stringProp\":\"SignalR!\",\"doubleProp\":6.2831853071,\"intProp\":42,\"dateTimeProp\":\"2017-04-11T00:00:00\",\"byteArrProp\":\"AQID\"}]}"),
- new JsonProtocolTestData("StreamInvocationMessage_HasCustomArgumentWithNullValueIgnoreAndNoCamelCase", new StreamInvocationMessage("123", "Target", null, new CustomObject()), false, NullValueHandling.Include, "{\"type\":4,\"invocationId\":\"123\",\"target\":\"Target\",\"arguments\":[{\"StringProp\":\"SignalR!\",\"DoubleProp\":6.2831853071,\"IntProp\":42,\"DateTimeProp\":\"2017-04-11T00:00:00\",\"NullProp\":null,\"ByteArrProp\":\"AQID\"}]}"),
- new JsonProtocolTestData("StreamInvocationMessage_HasCustomArgumentWithNullValueInclude", new StreamInvocationMessage("123", "Target", null, new CustomObject()), true, NullValueHandling.Include, "{\"type\":4,\"invocationId\":\"123\",\"target\":\"Target\",\"arguments\":[{\"stringProp\":\"SignalR!\",\"doubleProp\":6.2831853071,\"intProp\":42,\"dateTimeProp\":\"2017-04-11T00:00:00\",\"nullProp\":null,\"byteArrProp\":\"AQID\"}]}"),
- new JsonProtocolTestData("StreamInvocationMessage_HasHeaders", AddHeaders(TestHeaders, new StreamInvocationMessage("123", "Target", null, new CustomObject())), true, NullValueHandling.Include, "{\"type\":4," + SerializedHeaders + ",\"invocationId\":\"123\",\"target\":\"Target\",\"arguments\":[{\"stringProp\":\"SignalR!\",\"doubleProp\":6.2831853071,\"intProp\":42,\"dateTimeProp\":\"2017-04-11T00:00:00\",\"nullProp\":null,\"byteArrProp\":\"AQID\"}]}"),
+ new JsonProtocolTestData("StreamInvocationMessage_HasCustomArgumentWithNoCamelCase", new StreamInvocationMessage("123", "Target", null, new CustomObject()), false, NullValueHandling.Ignore, "{\"type\":4,\"invocationId\":\"123\",\"target\":\"Target\",\"arguments\":[{\"StringProp\":\"SignalR!\",\"DoubleProp\":6.2831853071,\"IntProp\":42,\"DateTimeProp\":\"2017-04-11T00:00:00Z\",\"ByteArrProp\":\"AQID\"}]}"),
+ new JsonProtocolTestData("StreamInvocationMessage_HasCustomArgumentWithNullValueIgnore", new StreamInvocationMessage("123", "Target", null, new CustomObject()), true, NullValueHandling.Ignore, "{\"type\":4,\"invocationId\":\"123\",\"target\":\"Target\",\"arguments\":[{\"stringProp\":\"SignalR!\",\"doubleProp\":6.2831853071,\"intProp\":42,\"dateTimeProp\":\"2017-04-11T00:00:00Z\",\"byteArrProp\":\"AQID\"}]}"),
+ new JsonProtocolTestData("StreamInvocationMessage_HasCustomArgumentWithNullValueIgnoreAndNoCamelCase", new StreamInvocationMessage("123", "Target", null, new CustomObject()), false, NullValueHandling.Include, "{\"type\":4,\"invocationId\":\"123\",\"target\":\"Target\",\"arguments\":[{\"StringProp\":\"SignalR!\",\"DoubleProp\":6.2831853071,\"IntProp\":42,\"DateTimeProp\":\"2017-04-11T00:00:00Z\",\"NullProp\":null,\"ByteArrProp\":\"AQID\"}]}"),
+ new JsonProtocolTestData("StreamInvocationMessage_HasCustomArgumentWithNullValueInclude", new StreamInvocationMessage("123", "Target", null, new CustomObject()), true, NullValueHandling.Include, "{\"type\":4,\"invocationId\":\"123\",\"target\":\"Target\",\"arguments\":[{\"stringProp\":\"SignalR!\",\"doubleProp\":6.2831853071,\"intProp\":42,\"dateTimeProp\":\"2017-04-11T00:00:00Z\",\"nullProp\":null,\"byteArrProp\":\"AQID\"}]}"),
+ new JsonProtocolTestData("StreamInvocationMessage_HasHeaders", AddHeaders(TestHeaders, new StreamInvocationMessage("123", "Target", null, new CustomObject())), true, NullValueHandling.Include, "{\"type\":4," + SerializedHeaders + ",\"invocationId\":\"123\",\"target\":\"Target\",\"arguments\":[{\"stringProp\":\"SignalR!\",\"doubleProp\":6.2831853071,\"intProp\":42,\"dateTimeProp\":\"2017-04-11T00:00:00Z\",\"nullProp\":null,\"byteArrProp\":\"AQID\"}]}"),
new JsonProtocolTestData("CancelInvocationMessage_HasInvocationId", new CancelInvocationMessage("123"), true, NullValueHandling.Ignore, "{\"type\":5,\"invocationId\":\"123\"}"),
new JsonProtocolTestData("CancelInvocationMessage_HasHeaders", AddHeaders(TestHeaders, new CancelInvocationMessage("123")), true, NullValueHandling.Ignore, "{\"type\":5," + SerializedHeaders + ",\"invocationId\":\"123\"}"),
diff --git a/test/Microsoft.AspNetCore.SignalR.Common.Tests/Internal/Protocol/MessagePackHelpers.cs b/test/Microsoft.AspNetCore.SignalR.Common.Tests/Internal/Protocol/MessagePackHelpers.cs
deleted file mode 100644
index 2c9eafb327..0000000000
--- a/test/Microsoft.AspNetCore.SignalR.Common.Tests/Internal/Protocol/MessagePackHelpers.cs
+++ /dev/null
@@ -1,15 +0,0 @@
-using System;
-using System.Linq;
-using MsgPack;
-
-namespace Microsoft.AspNetCore.SignalR.Common.Tests.Internal.Protocol
-{
- public static class MessagePackHelpers
- {
- public static MessagePackObject Array(params MessagePackObject[] items) =>
- new MessagePackObject(items);
-
- public static MessagePackObject Map(params (MessagePackObject Key, MessagePackObject Value)[] items) =>
- new MessagePackObject(new MessagePackObjectDictionary(items.ToDictionary(i => i.Key, i => i.Value)));
- }
-}
diff --git a/test/Microsoft.AspNetCore.SignalR.Common.Tests/Internal/Protocol/MessagePackHubProtocolTests.cs b/test/Microsoft.AspNetCore.SignalR.Common.Tests/Internal/Protocol/MessagePackHubProtocolTests.cs
index e6bdb6090d..2e3d7e9d31 100644
--- a/test/Microsoft.AspNetCore.SignalR.Common.Tests/Internal/Protocol/MessagePackHubProtocolTests.cs
+++ b/test/Microsoft.AspNetCore.SignalR.Common.Tests/Internal/Protocol/MessagePackHubProtocolTests.cs
@@ -4,19 +4,17 @@
using System;
using System.Buffers;
using System.Collections.Generic;
+using System.Diagnostics;
using System.IO;
using System.Linq;
-using System.Text;
using Microsoft.AspNetCore.Internal;
using Microsoft.AspNetCore.SignalR.Internal.Formatters;
using Microsoft.AspNetCore.SignalR.Internal.Protocol;
-using MsgPack;
using Xunit;
namespace Microsoft.AspNetCore.SignalR.Common.Tests.Internal.Protocol
{
using static HubMessageHelpers;
- using static MessagePackHelpers;
public class MessagePackHubProtocolTests
{
@@ -27,36 +25,22 @@ namespace Microsoft.AspNetCore.SignalR.Common.Tests.Internal.Protocol
{ "ValueWithNewLines", "Also\nWorks\r\nFine" },
};
- private static readonly MessagePackObject TestHeadersSerialized = Map(
- ("Foo", "Bar"),
- ("KeyWith\nNew\r\nLines", "Still Works"),
- ("ValueWithNewLines", "Also\nWorks\r\nFine"));
-
private static readonly MessagePackHubProtocol _hubProtocol
= new MessagePackHubProtocol();
- private static readonly MessagePackObject CustomObjectSerialized = Map(
- ("ByteArrProp", new MessagePackObject(new byte[] { 1, 2, 3 }, isBinary: true)),
- ("DateTimeProp", new MessagePackObject(Timestamp.FromDateTime(new DateTime(2017, 4, 11)))),
- ("DoubleProp", 6.2831853071),
- ("IntProp", 42),
- ("NullProp", MessagePackObject.Nil),
- ("StringProp", "SignalR!"));
+ public enum TestEnum
+ {
+ Zero = 0,
+ One
+ }
// Test Data for Parse/WriteMessages:
// * Name: A string name that is used when reporting the test (it's the ToString value for ProtocolTestData)
// * Message: The HubMessage that is either expected (in Parse) or used as input (in Write)
- // * Encoded: Raw MessagePackObject values (using the MessagePackHelpers static "Arr" and "Map" helpers) describing the message
- // * Binary: Base64-encoded binary "baseline" to sanity-check MsgPack-Cli behavior
+ // * Binary: Base64-encoded binary "baseline" to sanity-check MessagePack-CSharp behavior
//
- // The Encoded value is used as input to "Parse" and as the expected output that is verified in "Write". So if our encoding changes,
- // those values will change and the Assert will give you a useful error telling you how the MsgPack structure itself changed (rather than just
- // a bunch of random bytes). However, we want to be sure MsgPack-Cli doesn't change behavior, so we also verify that the binary encoding
- // matches our expectation by comparing against a base64-string.
- //
- // If you change MsgPack encoding, you should update the 'encoded' values for these items, and then re-run the test. You'll get a failure which will
- // provide a new Base64 binary string to replace in the 'binary' value. Use a tool like https://sugendran.github.io/msgpack-visualizer/ to verify
- // that the MsgPack is correct and then just replace the Base64 value.
+ // When changing the tests/message pack parsing if you get test failures look at the base64 encoding and
+ // use a tool like https://sugendran.github.io/msgpack-visualizer/ to verify that the MsgPack is correct and then just replace the Base64 value.
public static IEnumerable