Swtich to MessagePack-CSharp (#1879)
This commit is contained in:
parent
ecd665c471
commit
6d050140e5
|
|
@ -57,7 +57,7 @@
|
|||
<MicrosoftNETCoreApp21PackageVersion>2.1.0-preview2-26403-06</MicrosoftNETCoreApp21PackageVersion>
|
||||
<MicrosoftNETTestSdkPackageVersion>15.6.1</MicrosoftNETTestSdkPackageVersion>
|
||||
<MoqPackageVersion>4.7.49</MoqPackageVersion>
|
||||
<MsgPackCliPackageVersion>1.0.0-rc</MsgPackCliPackageVersion>
|
||||
<MessagePackPackageVersion>1.7.3.4</MessagePackPackageVersion>
|
||||
<NewtonsoftJsonPackageVersion>11.0.2</NewtonsoftJsonPackageVersion>
|
||||
<StackExchangeRedisStrongNamePackageVersion>1.2.4</StackExchangeRedisStrongNamePackageVersion>
|
||||
<SystemBuffersPackageVersion>4.5.0-preview2-26403-05</SystemBuffersPackageVersion>
|
||||
|
|
|
|||
|
|
@ -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; }
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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",
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
})
|
||||
|
|
|
|||
|
|
@ -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"
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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",
|
||||
|
|
|
|||
|
|
@ -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 =>
|
||||
|
|
|
|||
|
|
@ -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<MessagePackHubProtocolOptions> 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<byte> GetArraySegment(in ReadOnlySequence<byte> input)
|
||||
|
|
@ -77,41 +101,39 @@ namespace Microsoft.AspNetCore.SignalR.Internal.Protocol
|
|||
return new ArraySegment<byte>(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<string, string> ReadHeaders(Unpacker unpacker)
|
||||
private static Dictionary<string, string> 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<Type> parameterTypes)
|
||||
private static object[] BindArguments(byte[] input, ref int offset, IReadOnlyList<Type> 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<string, string> headers)
|
||||
private void PackHeaders(Stream packer, IDictionary<string, string> 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<byte>(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<IFormatterResolver> 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<IFormatterResolver>(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<IFormatterResolver> Resolvers = new[]
|
||||
{
|
||||
MessagePack.Resolvers.DynamicEnumAsStringResolver.Instance,
|
||||
MessagePack.Resolvers.ContractlessStandardResolver.Instance,
|
||||
};
|
||||
|
||||
public IMessagePackFormatter<T> GetFormatter<T>()
|
||||
{
|
||||
return Cache<T>.Formatter;
|
||||
}
|
||||
|
||||
private static class Cache<T>
|
||||
{
|
||||
public static readonly IMessagePackFormatter<T> Formatter;
|
||||
|
||||
static Cache()
|
||||
{
|
||||
foreach (var resolver in Resolvers)
|
||||
{
|
||||
Formatter = resolver.GetFormatter<T>();
|
||||
if (Formatter != null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Support for users making their own Formatter lists
|
||||
internal class CombinedResolvers : IFormatterResolver
|
||||
{
|
||||
private readonly IList<IFormatterResolver> _resolvers;
|
||||
|
||||
public CombinedResolvers(IList<IFormatterResolver> resolvers)
|
||||
{
|
||||
_resolvers = resolvers;
|
||||
}
|
||||
|
||||
public IMessagePackFormatter<T> GetFormatter<T>()
|
||||
{
|
||||
foreach (var resolver in _resolvers)
|
||||
{
|
||||
var formatter = resolver.GetFormatter<T>();
|
||||
if (formatter != null)
|
||||
{
|
||||
return formatter;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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<IFormatterResolver> FormatterResolvers { get; set; } = MessagePackHubProtocol.CreateDefaultFormatterResolvers();
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -12,7 +12,7 @@
|
|||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="MsgPack.Cli" Version="$(MsgPackCliPackageVersion)" />
|
||||
<PackageReference Include="MessagePack" Version="$(MessagePackPackageVersion)" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
|
|
|
|||
|
|
@ -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<MessagePackHubProtocol>(serviceProvider.GetService<IHubProtocol>());
|
||||
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<MessagePackHubProtocol>(serviceProvider.GetService<IHubProtocol>());
|
||||
Assert.Equal(SerializationMethod.Array, actualProtocol.SerializationContext.SerializationMethod);
|
||||
Assert.IsType<MessagePackHubProtocol>(serviceProvider.GetService<IHubProtocol>());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
||||
|
|
|
|||
|
|
@ -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\"}"),
|
||||
|
|
|
|||
|
|
@ -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)));
|
||||
}
|
||||
}
|
||||
|
|
@ -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<object[]> TestDataNames
|
||||
{
|
||||
|
|
@ -75,202 +59,180 @@ namespace Microsoft.AspNetCore.SignalR.Common.Tests.Internal.Protocol
|
|||
new ProtocolTestData(
|
||||
name: "InvocationWithNoHeadersAndNoArgs",
|
||||
message: new InvocationMessage(invocationId: "xyz", target: "method", argumentBindingException: null),
|
||||
encoded: Array(HubProtocolConstants.InvocationMessageType, Map(), "xyz", "method", Array()),
|
||||
binary: "lQGAo3h5eqZtZXRob2SQ"),
|
||||
new ProtocolTestData(
|
||||
name: "InvocationWithNoHeadersNoIdAndNoArgs",
|
||||
message: new InvocationMessage(target: "method", argumentBindingException: null),
|
||||
encoded: Array(HubProtocolConstants.InvocationMessageType, Map(), MessagePackObject.Nil, "method", Array()),
|
||||
binary: "lQGAwKZtZXRob2SQ"),
|
||||
new ProtocolTestData(
|
||||
name: "InvocationWithNoHeadersNoIdAndSingleNullArg",
|
||||
message: new InvocationMessage(target: "method", argumentBindingException: null, new object[] { null }),
|
||||
encoded: Array(HubProtocolConstants.InvocationMessageType, Map(), MessagePackObject.Nil, "method", Array(MessagePackObject.Nil)),
|
||||
binary: "lQGAwKZtZXRob2SRwA=="),
|
||||
new ProtocolTestData(
|
||||
name: "InvocationWithNoHeadersNoIdAndSingleIntArg",
|
||||
message: new InvocationMessage(target: "method", argumentBindingException: null, 42),
|
||||
encoded: Array(HubProtocolConstants.InvocationMessageType, Map(), MessagePackObject.Nil, "method", Array(42)),
|
||||
binary: "lQGAwKZtZXRob2SRKg=="),
|
||||
new ProtocolTestData(
|
||||
name: "InvocationWithNoHeadersNoIdIntAndStringArgs",
|
||||
message: new InvocationMessage(target: "method", argumentBindingException: null, 42, "string"),
|
||||
encoded: Array(HubProtocolConstants.InvocationMessageType, Map(), MessagePackObject.Nil, "method", Array(42, "string")),
|
||||
binary: "lQGAwKZtZXRob2SSKqZzdHJpbmc="),
|
||||
new ProtocolTestData(
|
||||
name: "InvocationWithNoHeadersNoIdIntAndEnumArgs",
|
||||
message: new InvocationMessage(target: "method", argumentBindingException: null, 42, TestEnum.One),
|
||||
binary: "lQGAwKZtZXRob2SSKqNPbmU="),
|
||||
new ProtocolTestData(
|
||||
name: "InvocationWithNoHeadersNoIdAndCustomObjectArg",
|
||||
message: new InvocationMessage(target: "method", argumentBindingException: null, 42, "string", new CustomObject()),
|
||||
encoded: Array(HubProtocolConstants.InvocationMessageType, Map(), MessagePackObject.Nil, "method", Array(42, "string", CustomObjectSerialized)),
|
||||
binary: "lQGAwKZtZXRob2STKqZzdHJpbmeGq0J5dGVBcnJQcm9wxAMBAgOsRGF0ZVRpbWVQcm9w1v9Y7ByAqkRvdWJsZVByb3DLQBkh+1RCzxKnSW50UHJvcCqoTnVsbFByb3DAqlN0cmluZ1Byb3CoU2lnbmFsUiE="),
|
||||
binary: "lQGAwKZtZXRob2STKqZzdHJpbmeGqlN0cmluZ1Byb3CoU2lnbmFsUiGqRG91YmxlUHJvcMtAGSH7VELPEqdJbnRQcm9wKqxEYXRlVGltZVByb3DW/1jsHICoTnVsbFByb3DAq0J5dGVBcnJQcm9wxAMBAgM="),
|
||||
new ProtocolTestData(
|
||||
name: "InvocationWithNoHeadersNoIdAndArrayOfCustomObjectArgs",
|
||||
message: new InvocationMessage(target: "method", argumentBindingException: null, new[] { new CustomObject(), new CustomObject() }),
|
||||
encoded: Array(HubProtocolConstants.InvocationMessageType, Map(), MessagePackObject.Nil, "method", Array(CustomObjectSerialized, CustomObjectSerialized)),
|
||||
binary: "lQGAwKZtZXRob2SShqtCeXRlQXJyUHJvcMQDAQIDrERhdGVUaW1lUHJvcNb/WOwcgKpEb3VibGVQcm9wy0AZIftUQs8Sp0ludFByb3AqqE51bGxQcm9wwKpTdHJpbmdQcm9wqFNpZ25hbFIhhqtCeXRlQXJyUHJvcMQDAQIDrERhdGVUaW1lUHJvcNb/WOwcgKpEb3VibGVQcm9wy0AZIftUQs8Sp0ludFByb3AqqE51bGxQcm9wwKpTdHJpbmdQcm9wqFNpZ25hbFIh"),
|
||||
binary: "lQGAwKZtZXRob2SShqpTdHJpbmdQcm9wqFNpZ25hbFIhqkRvdWJsZVByb3DLQBkh+1RCzxKnSW50UHJvcCqsRGF0ZVRpbWVQcm9w1v9Y7ByAqE51bGxQcm9wwKtCeXRlQXJyUHJvcMQDAQIDhqpTdHJpbmdQcm9wqFNpZ25hbFIhqkRvdWJsZVByb3DLQBkh+1RCzxKnSW50UHJvcCqsRGF0ZVRpbWVQcm9w1v9Y7ByAqE51bGxQcm9wwKtCeXRlQXJyUHJvcMQDAQID"),
|
||||
new ProtocolTestData(
|
||||
name: "InvocationWithHeadersNoIdAndArrayOfCustomObjectArgs",
|
||||
message: AddHeaders(TestHeaders, new InvocationMessage(target: "method", argumentBindingException: null, new[] { new CustomObject(), new CustomObject() })),
|
||||
encoded: Array(HubProtocolConstants.InvocationMessageType, TestHeadersSerialized, MessagePackObject.Nil, "method", Array(CustomObjectSerialized, CustomObjectSerialized)),
|
||||
binary: "lQGDo0Zvb6NCYXKyS2V5V2l0aApOZXcNCkxpbmVzq1N0aWxsIFdvcmtzsVZhbHVlV2l0aE5ld0xpbmVzsEFsc28KV29ya3MNCkZpbmXApm1ldGhvZJKGq0J5dGVBcnJQcm9wxAMBAgOsRGF0ZVRpbWVQcm9w1v9Y7ByAqkRvdWJsZVByb3DLQBkh+1RCzxKnSW50UHJvcCqoTnVsbFByb3DAqlN0cmluZ1Byb3CoU2lnbmFsUiGGq0J5dGVBcnJQcm9wxAMBAgOsRGF0ZVRpbWVQcm9w1v9Y7ByAqkRvdWJsZVByb3DLQBkh+1RCzxKnSW50UHJvcCqoTnVsbFByb3DAqlN0cmluZ1Byb3CoU2lnbmFsUiE="),
|
||||
binary: "lQGDo0Zvb6NCYXKyS2V5V2l0aApOZXcNCkxpbmVzq1N0aWxsIFdvcmtzsVZhbHVlV2l0aE5ld0xpbmVzsEFsc28KV29ya3MNCkZpbmXApm1ldGhvZJKGqlN0cmluZ1Byb3CoU2lnbmFsUiGqRG91YmxlUHJvcMtAGSH7VELPEqdJbnRQcm9wKqxEYXRlVGltZVByb3DW/1jsHICoTnVsbFByb3DAq0J5dGVBcnJQcm9wxAMBAgOGqlN0cmluZ1Byb3CoU2lnbmFsUiGqRG91YmxlUHJvcMtAGSH7VELPEqdJbnRQcm9wKqxEYXRlVGltZVByb3DW/1jsHICoTnVsbFByb3DAq0J5dGVBcnJQcm9wxAMBAgM="),
|
||||
|
||||
// StreamItem Messages
|
||||
new ProtocolTestData(
|
||||
name: "StreamItemWithNoHeadersAndNullItem",
|
||||
message: new StreamItemMessage(invocationId: "xyz", item: null),
|
||||
encoded: Array(HubProtocolConstants.StreamItemMessageType, Map(), "xyz", MessagePackObject.Nil),
|
||||
binary: "lAKAo3h5esA="),
|
||||
new ProtocolTestData(
|
||||
name: "StreamItemWithNoHeadersAndIntItem",
|
||||
message: new StreamItemMessage(invocationId: "xyz", item: 42),
|
||||
encoded: Array(HubProtocolConstants.StreamItemMessageType, Map(), "xyz", 42),
|
||||
binary: "lAKAo3h5eio="),
|
||||
new ProtocolTestData(
|
||||
name: "StreamItemWithNoHeadersAndFloatItem",
|
||||
message: new StreamItemMessage(invocationId: "xyz", item: 42.0f),
|
||||
encoded: Array(HubProtocolConstants.StreamItemMessageType, Map(), "xyz", 42.0f),
|
||||
binary: "lAKAo3h5espCKAAA"),
|
||||
new ProtocolTestData(
|
||||
name: "StreamItemWithNoHeadersAndStringItem",
|
||||
message: new StreamItemMessage(invocationId: "xyz", item: "string"),
|
||||
encoded: Array(HubProtocolConstants.StreamItemMessageType, Map(), "xyz", "string"),
|
||||
binary: "lAKAo3h5eqZzdHJpbmc="),
|
||||
new ProtocolTestData(
|
||||
name: "StreamItemWithNoHeadersAndBoolItem",
|
||||
message: new StreamItemMessage(invocationId: "xyz", item: true),
|
||||
encoded: Array(HubProtocolConstants.StreamItemMessageType, Map(), "xyz", true),
|
||||
binary: "lAKAo3h5esM="),
|
||||
new ProtocolTestData(
|
||||
name: "StreamItemWithNoHeadersAndEnumItem",
|
||||
message: new StreamItemMessage(invocationId: "xyz", item: TestEnum.One),
|
||||
binary: "lAKAo3h5eqNPbmU="),
|
||||
new ProtocolTestData(
|
||||
name: "StreamItemWithNoHeadersAndCustomObjectItem",
|
||||
message: new StreamItemMessage(invocationId: "xyz", item: new CustomObject()),
|
||||
encoded: Array(HubProtocolConstants.StreamItemMessageType, Map(), "xyz", CustomObjectSerialized),
|
||||
binary: "lAKAo3h5eoarQnl0ZUFyclByb3DEAwECA6xEYXRlVGltZVByb3DW/1jsHICqRG91YmxlUHJvcMtAGSH7VELPEqdJbnRQcm9wKqhOdWxsUHJvcMCqU3RyaW5nUHJvcKhTaWduYWxSIQ=="),
|
||||
binary: "lAKAo3h5eoaqU3RyaW5nUHJvcKhTaWduYWxSIapEb3VibGVQcm9wy0AZIftUQs8Sp0ludFByb3AqrERhdGVUaW1lUHJvcNb/WOwcgKhOdWxsUHJvcMCrQnl0ZUFyclByb3DEAwECAw=="),
|
||||
new ProtocolTestData(
|
||||
name: "StreamItemWithNoHeadersAndCustomObjectArrayItem",
|
||||
message: new StreamItemMessage(invocationId: "xyz", item: new[] { new CustomObject(), new CustomObject() }),
|
||||
encoded: Array(HubProtocolConstants.StreamItemMessageType, Map(), "xyz", Array(CustomObjectSerialized, CustomObjectSerialized)),
|
||||
binary: "lAKAo3h5epKGq0J5dGVBcnJQcm9wxAMBAgOsRGF0ZVRpbWVQcm9w1v9Y7ByAqkRvdWJsZVByb3DLQBkh+1RCzxKnSW50UHJvcCqoTnVsbFByb3DAqlN0cmluZ1Byb3CoU2lnbmFsUiGGq0J5dGVBcnJQcm9wxAMBAgOsRGF0ZVRpbWVQcm9w1v9Y7ByAqkRvdWJsZVByb3DLQBkh+1RCzxKnSW50UHJvcCqoTnVsbFByb3DAqlN0cmluZ1Byb3CoU2lnbmFsUiE="),
|
||||
binary: "lAKAo3h5epKGqlN0cmluZ1Byb3CoU2lnbmFsUiGqRG91YmxlUHJvcMtAGSH7VELPEqdJbnRQcm9wKqxEYXRlVGltZVByb3DW/1jsHICoTnVsbFByb3DAq0J5dGVBcnJQcm9wxAMBAgOGqlN0cmluZ1Byb3CoU2lnbmFsUiGqRG91YmxlUHJvcMtAGSH7VELPEqdJbnRQcm9wKqxEYXRlVGltZVByb3DW/1jsHICoTnVsbFByb3DAq0J5dGVBcnJQcm9wxAMBAgM="),
|
||||
new ProtocolTestData(
|
||||
name: "StreamItemWithHeadersAndCustomObjectArrayItem",
|
||||
message: AddHeaders(TestHeaders, new StreamItemMessage(invocationId: "xyz", item: new[] { new CustomObject(), new CustomObject() })),
|
||||
encoded: Array(HubProtocolConstants.StreamItemMessageType, TestHeadersSerialized, "xyz", Array(CustomObjectSerialized, CustomObjectSerialized)),
|
||||
binary: "lAKDo0Zvb6NCYXKyS2V5V2l0aApOZXcNCkxpbmVzq1N0aWxsIFdvcmtzsVZhbHVlV2l0aE5ld0xpbmVzsEFsc28KV29ya3MNCkZpbmWjeHl6koarQnl0ZUFyclByb3DEAwECA6xEYXRlVGltZVByb3DW/1jsHICqRG91YmxlUHJvcMtAGSH7VELPEqdJbnRQcm9wKqhOdWxsUHJvcMCqU3RyaW5nUHJvcKhTaWduYWxSIYarQnl0ZUFyclByb3DEAwECA6xEYXRlVGltZVByb3DW/1jsHICqRG91YmxlUHJvcMtAGSH7VELPEqdJbnRQcm9wKqhOdWxsUHJvcMCqU3RyaW5nUHJvcKhTaWduYWxSIQ=="),
|
||||
binary: "lAKDo0Zvb6NCYXKyS2V5V2l0aApOZXcNCkxpbmVzq1N0aWxsIFdvcmtzsVZhbHVlV2l0aE5ld0xpbmVzsEFsc28KV29ya3MNCkZpbmWjeHl6koaqU3RyaW5nUHJvcKhTaWduYWxSIapEb3VibGVQcm9wy0AZIftUQs8Sp0ludFByb3AqrERhdGVUaW1lUHJvcNb/WOwcgKhOdWxsUHJvcMCrQnl0ZUFyclByb3DEAwECA4aqU3RyaW5nUHJvcKhTaWduYWxSIapEb3VibGVQcm9wy0AZIftUQs8Sp0ludFByb3AqrERhdGVUaW1lUHJvcNb/WOwcgKhOdWxsUHJvcMCrQnl0ZUFyclByb3DEAwECAw=="),
|
||||
|
||||
// Completion Messages
|
||||
new ProtocolTestData(
|
||||
name: "CompletionWithNoHeadersAndError",
|
||||
message: CompletionMessage.WithError(invocationId: "xyz", error: "Error not found!"),
|
||||
encoded: Array(HubProtocolConstants.CompletionMessageType, Map(), "xyz", 1, "Error not found!"),
|
||||
binary: "lQOAo3h5egGwRXJyb3Igbm90IGZvdW5kIQ=="),
|
||||
new ProtocolTestData(
|
||||
name: "CompletionWithHeadersAndError",
|
||||
message: AddHeaders(TestHeaders, CompletionMessage.WithError(invocationId: "xyz", error: "Error not found!")),
|
||||
encoded: Array(HubProtocolConstants.CompletionMessageType, TestHeadersSerialized, "xyz", 1, "Error not found!"),
|
||||
binary: "lQODo0Zvb6NCYXKyS2V5V2l0aApOZXcNCkxpbmVzq1N0aWxsIFdvcmtzsVZhbHVlV2l0aE5ld0xpbmVzsEFsc28KV29ya3MNCkZpbmWjeHl6AbBFcnJvciBub3QgZm91bmQh"),
|
||||
new ProtocolTestData(
|
||||
name: "CompletionWithNoHeadersAndNoResult",
|
||||
message: CompletionMessage.Empty(invocationId: "xyz"),
|
||||
encoded: Array(HubProtocolConstants.CompletionMessageType, Map(), "xyz", 2),
|
||||
binary: "lAOAo3h5egI="),
|
||||
new ProtocolTestData(
|
||||
name: "CompletionWithHeadersAndNoResult",
|
||||
message: AddHeaders(TestHeaders, CompletionMessage.Empty(invocationId: "xyz")),
|
||||
encoded: Array(HubProtocolConstants.CompletionMessageType, TestHeadersSerialized, "xyz", 2),
|
||||
binary: "lAODo0Zvb6NCYXKyS2V5V2l0aApOZXcNCkxpbmVzq1N0aWxsIFdvcmtzsVZhbHVlV2l0aE5ld0xpbmVzsEFsc28KV29ya3MNCkZpbmWjeHl6Ag=="),
|
||||
new ProtocolTestData(
|
||||
name: "CompletionWithNoHeadersAndNullResult",
|
||||
message: CompletionMessage.WithResult(invocationId: "xyz", payload: null),
|
||||
encoded: Array(HubProtocolConstants.CompletionMessageType, Map(), "xyz", 3, MessagePackObject.Nil),
|
||||
binary: "lQOAo3h5egPA"),
|
||||
new ProtocolTestData(
|
||||
name: "CompletionWithNoHeadersAndIntResult",
|
||||
message: CompletionMessage.WithResult(invocationId: "xyz", payload: 42),
|
||||
encoded: Array(HubProtocolConstants.CompletionMessageType, Map(), "xyz", 3, 42),
|
||||
binary: "lQOAo3h5egMq"),
|
||||
new ProtocolTestData(
|
||||
name: "CompletionWithNoHeadersAndEnumResult",
|
||||
message: CompletionMessage.WithResult(invocationId: "xyz", payload: TestEnum.One),
|
||||
binary: "lQOAo3h5egOjT25l"),
|
||||
new ProtocolTestData(
|
||||
name: "CompletionWithNoHeadersAndFloatResult",
|
||||
message: CompletionMessage.WithResult(invocationId: "xyz", payload: 42.0f),
|
||||
encoded: Array(HubProtocolConstants.CompletionMessageType, Map(), "xyz", 3, 42.0f),
|
||||
binary: "lQOAo3h5egPKQigAAA=="),
|
||||
new ProtocolTestData(
|
||||
name: "CompletionWithNoHeadersAndStringResult",
|
||||
message: CompletionMessage.WithResult(invocationId: "xyz", payload: "string"),
|
||||
encoded: Array(HubProtocolConstants.CompletionMessageType, Map(), "xyz", 3, "string"),
|
||||
binary: "lQOAo3h5egOmc3RyaW5n"),
|
||||
new ProtocolTestData(
|
||||
name: "CompletionWithNoHeadersAndBooleanResult",
|
||||
message: CompletionMessage.WithResult(invocationId: "xyz", payload: true),
|
||||
encoded: Array(HubProtocolConstants.CompletionMessageType, Map(), "xyz", 3, true),
|
||||
binary: "lQOAo3h5egPD"),
|
||||
new ProtocolTestData(
|
||||
name: "CompletionWithNoHeadersAndCustomObjectResult",
|
||||
message: CompletionMessage.WithResult(invocationId: "xyz", payload: new CustomObject()),
|
||||
encoded: Array(HubProtocolConstants.CompletionMessageType, Map(), "xyz", 3, CustomObjectSerialized),
|
||||
binary: "lQOAo3h5egOGq0J5dGVBcnJQcm9wxAMBAgOsRGF0ZVRpbWVQcm9w1v9Y7ByAqkRvdWJsZVByb3DLQBkh+1RCzxKnSW50UHJvcCqoTnVsbFByb3DAqlN0cmluZ1Byb3CoU2lnbmFsUiE="),
|
||||
binary: "lQOAo3h5egOGqlN0cmluZ1Byb3CoU2lnbmFsUiGqRG91YmxlUHJvcMtAGSH7VELPEqdJbnRQcm9wKqxEYXRlVGltZVByb3DW/1jsHICoTnVsbFByb3DAq0J5dGVBcnJQcm9wxAMBAgM="),
|
||||
new ProtocolTestData(
|
||||
name: "CompletionWithNoHeadersAndCustomObjectArrayResult",
|
||||
message: CompletionMessage.WithResult(invocationId: "xyz", payload: new[] { new CustomObject(), new CustomObject() }),
|
||||
encoded: Array(HubProtocolConstants.CompletionMessageType, Map(), "xyz", 3, Array(CustomObjectSerialized, CustomObjectSerialized)),
|
||||
binary: "lQOAo3h5egOShqtCeXRlQXJyUHJvcMQDAQIDrERhdGVUaW1lUHJvcNb/WOwcgKpEb3VibGVQcm9wy0AZIftUQs8Sp0ludFByb3AqqE51bGxQcm9wwKpTdHJpbmdQcm9wqFNpZ25hbFIhhqtCeXRlQXJyUHJvcMQDAQIDrERhdGVUaW1lUHJvcNb/WOwcgKpEb3VibGVQcm9wy0AZIftUQs8Sp0ludFByb3AqqE51bGxQcm9wwKpTdHJpbmdQcm9wqFNpZ25hbFIh"),
|
||||
binary: "lQOAo3h5egOShqpTdHJpbmdQcm9wqFNpZ25hbFIhqkRvdWJsZVByb3DLQBkh+1RCzxKnSW50UHJvcCqsRGF0ZVRpbWVQcm9w1v9Y7ByAqE51bGxQcm9wwKtCeXRlQXJyUHJvcMQDAQIDhqpTdHJpbmdQcm9wqFNpZ25hbFIhqkRvdWJsZVByb3DLQBkh+1RCzxKnSW50UHJvcCqsRGF0ZVRpbWVQcm9w1v9Y7ByAqE51bGxQcm9wwKtCeXRlQXJyUHJvcMQDAQID"),
|
||||
new ProtocolTestData(
|
||||
name: "CompletionWithHeadersAndCustomObjectArrayResult",
|
||||
message: AddHeaders(TestHeaders, CompletionMessage.WithResult(invocationId: "xyz", payload: new[] { new CustomObject(), new CustomObject() })),
|
||||
encoded: Array(HubProtocolConstants.CompletionMessageType, TestHeadersSerialized, "xyz", 3, Array(CustomObjectSerialized, CustomObjectSerialized)),
|
||||
binary: "lQODo0Zvb6NCYXKyS2V5V2l0aApOZXcNCkxpbmVzq1N0aWxsIFdvcmtzsVZhbHVlV2l0aE5ld0xpbmVzsEFsc28KV29ya3MNCkZpbmWjeHl6A5KGq0J5dGVBcnJQcm9wxAMBAgOsRGF0ZVRpbWVQcm9w1v9Y7ByAqkRvdWJsZVByb3DLQBkh+1RCzxKnSW50UHJvcCqoTnVsbFByb3DAqlN0cmluZ1Byb3CoU2lnbmFsUiGGq0J5dGVBcnJQcm9wxAMBAgOsRGF0ZVRpbWVQcm9w1v9Y7ByAqkRvdWJsZVByb3DLQBkh+1RCzxKnSW50UHJvcCqoTnVsbFByb3DAqlN0cmluZ1Byb3CoU2lnbmFsUiE="),
|
||||
binary: "lQODo0Zvb6NCYXKyS2V5V2l0aApOZXcNCkxpbmVzq1N0aWxsIFdvcmtzsVZhbHVlV2l0aE5ld0xpbmVzsEFsc28KV29ya3MNCkZpbmWjeHl6A5KGqlN0cmluZ1Byb3CoU2lnbmFsUiGqRG91YmxlUHJvcMtAGSH7VELPEqdJbnRQcm9wKqxEYXRlVGltZVByb3DW/1jsHICoTnVsbFByb3DAq0J5dGVBcnJQcm9wxAMBAgOGqlN0cmluZ1Byb3CoU2lnbmFsUiGqRG91YmxlUHJvcMtAGSH7VELPEqdJbnRQcm9wKqxEYXRlVGltZVByb3DW/1jsHICoTnVsbFByb3DAq0J5dGVBcnJQcm9wxAMBAgM="),
|
||||
|
||||
// StreamInvocation Messages
|
||||
new ProtocolTestData(
|
||||
name: "StreamInvocationWithNoHeadersAndNoArgs",
|
||||
message: new StreamInvocationMessage(invocationId: "xyz", target: "method", argumentBindingException: null),
|
||||
encoded: Array(HubProtocolConstants.StreamInvocationMessageType, Map(), "xyz", "method", Array()),
|
||||
binary: "lQSAo3h5eqZtZXRob2SQ"),
|
||||
new ProtocolTestData(
|
||||
name: "StreamInvocationWithNoHeadersAndNullArg",
|
||||
message: new StreamInvocationMessage(invocationId: "xyz", target: "method", argumentBindingException: null, new object[] { null }),
|
||||
encoded: Array(HubProtocolConstants.StreamInvocationMessageType, Map(), "xyz", "method", Array(MessagePackObject.Nil)),
|
||||
binary: "lQSAo3h5eqZtZXRob2SRwA=="),
|
||||
new ProtocolTestData(
|
||||
name: "StreamInvocationWithNoHeadersAndIntArg",
|
||||
message: new StreamInvocationMessage(invocationId: "xyz", target: "method", argumentBindingException: null, 42),
|
||||
encoded: Array(HubProtocolConstants.StreamInvocationMessageType, Map(), "xyz", "method", Array(42)),
|
||||
binary: "lQSAo3h5eqZtZXRob2SRKg=="),
|
||||
new ProtocolTestData(
|
||||
name: "StreamInvocationWithNoHeadersAndEnumArg",
|
||||
message: new StreamInvocationMessage(invocationId: "xyz", target: "method", argumentBindingException: null, TestEnum.One),
|
||||
binary: "lQSAo3h5eqZtZXRob2SRo09uZQ=="),
|
||||
new ProtocolTestData(
|
||||
name: "StreamInvocationWithNoHeadersAndIntAndStringArgs",
|
||||
message: new StreamInvocationMessage(invocationId: "xyz", target: "method", argumentBindingException: null, 42, "string"),
|
||||
encoded: Array(HubProtocolConstants.StreamInvocationMessageType, Map(), "xyz", "method", Array(42, "string")),
|
||||
binary: "lQSAo3h5eqZtZXRob2SSKqZzdHJpbmc="),
|
||||
new ProtocolTestData(
|
||||
name: "StreamInvocationWithNoHeadersAndIntStringAndCustomObjectArgs",
|
||||
message: new StreamInvocationMessage(invocationId: "xyz", target: "method", argumentBindingException: null, 42, "string", new CustomObject()),
|
||||
encoded: Array(HubProtocolConstants.StreamInvocationMessageType, Map(), "xyz", "method", Array(42, "string", CustomObjectSerialized)),
|
||||
binary: "lQSAo3h5eqZtZXRob2STKqZzdHJpbmeGq0J5dGVBcnJQcm9wxAMBAgOsRGF0ZVRpbWVQcm9w1v9Y7ByAqkRvdWJsZVByb3DLQBkh+1RCzxKnSW50UHJvcCqoTnVsbFByb3DAqlN0cmluZ1Byb3CoU2lnbmFsUiE="),
|
||||
binary: "lQSAo3h5eqZtZXRob2STKqZzdHJpbmeGqlN0cmluZ1Byb3CoU2lnbmFsUiGqRG91YmxlUHJvcMtAGSH7VELPEqdJbnRQcm9wKqxEYXRlVGltZVByb3DW/1jsHICoTnVsbFByb3DAq0J5dGVBcnJQcm9wxAMBAgM="),
|
||||
new ProtocolTestData(
|
||||
name: "StreamInvocationWithNoHeadersAndCustomObjectArrayArg",
|
||||
message: new StreamInvocationMessage(invocationId: "xyz", target: "method", argumentBindingException: null, new[] { new CustomObject(), new CustomObject() }),
|
||||
encoded: Array(HubProtocolConstants.StreamInvocationMessageType, Map(), "xyz", "method", Array(CustomObjectSerialized, CustomObjectSerialized)),
|
||||
binary: "lQSAo3h5eqZtZXRob2SShqtCeXRlQXJyUHJvcMQDAQIDrERhdGVUaW1lUHJvcNb/WOwcgKpEb3VibGVQcm9wy0AZIftUQs8Sp0ludFByb3AqqE51bGxQcm9wwKpTdHJpbmdQcm9wqFNpZ25hbFIhhqtCeXRlQXJyUHJvcMQDAQIDrERhdGVUaW1lUHJvcNb/WOwcgKpEb3VibGVQcm9wy0AZIftUQs8Sp0ludFByb3AqqE51bGxQcm9wwKpTdHJpbmdQcm9wqFNpZ25hbFIh"),
|
||||
binary: "lQSAo3h5eqZtZXRob2SShqpTdHJpbmdQcm9wqFNpZ25hbFIhqkRvdWJsZVByb3DLQBkh+1RCzxKnSW50UHJvcCqsRGF0ZVRpbWVQcm9w1v9Y7ByAqE51bGxQcm9wwKtCeXRlQXJyUHJvcMQDAQIDhqpTdHJpbmdQcm9wqFNpZ25hbFIhqkRvdWJsZVByb3DLQBkh+1RCzxKnSW50UHJvcCqsRGF0ZVRpbWVQcm9w1v9Y7ByAqE51bGxQcm9wwKtCeXRlQXJyUHJvcMQDAQID"),
|
||||
new ProtocolTestData(
|
||||
name: "StreamInvocationWithHeadersAndCustomObjectArrayArg",
|
||||
message: AddHeaders(TestHeaders, new StreamInvocationMessage(invocationId: "xyz", target: "method", argumentBindingException: null, new[] { new CustomObject(), new CustomObject() })),
|
||||
encoded: Array(HubProtocolConstants.StreamInvocationMessageType, TestHeadersSerialized, "xyz", "method", Array(CustomObjectSerialized, CustomObjectSerialized)),
|
||||
binary: "lQSDo0Zvb6NCYXKyS2V5V2l0aApOZXcNCkxpbmVzq1N0aWxsIFdvcmtzsVZhbHVlV2l0aE5ld0xpbmVzsEFsc28KV29ya3MNCkZpbmWjeHl6pm1ldGhvZJKGq0J5dGVBcnJQcm9wxAMBAgOsRGF0ZVRpbWVQcm9w1v9Y7ByAqkRvdWJsZVByb3DLQBkh+1RCzxKnSW50UHJvcCqoTnVsbFByb3DAqlN0cmluZ1Byb3CoU2lnbmFsUiGGq0J5dGVBcnJQcm9wxAMBAgOsRGF0ZVRpbWVQcm9w1v9Y7ByAqkRvdWJsZVByb3DLQBkh+1RCzxKnSW50UHJvcCqoTnVsbFByb3DAqlN0cmluZ1Byb3CoU2lnbmFsUiE="),
|
||||
binary: "lQSDo0Zvb6NCYXKyS2V5V2l0aApOZXcNCkxpbmVzq1N0aWxsIFdvcmtzsVZhbHVlV2l0aE5ld0xpbmVzsEFsc28KV29ya3MNCkZpbmWjeHl6pm1ldGhvZJKGqlN0cmluZ1Byb3CoU2lnbmFsUiGqRG91YmxlUHJvcMtAGSH7VELPEqdJbnRQcm9wKqxEYXRlVGltZVByb3DW/1jsHICoTnVsbFByb3DAq0J5dGVBcnJQcm9wxAMBAgOGqlN0cmluZ1Byb3CoU2lnbmFsUiGqRG91YmxlUHJvcMtAGSH7VELPEqdJbnRQcm9wKqxEYXRlVGltZVByb3DW/1jsHICoTnVsbFByb3DAq0J5dGVBcnJQcm9wxAMBAgM="),
|
||||
|
||||
// CancelInvocation Messages
|
||||
new ProtocolTestData(
|
||||
name: "CancelInvocationWithNoHeaders",
|
||||
message: new CancelInvocationMessage(invocationId: "xyz"),
|
||||
encoded: Array(HubProtocolConstants.CancelInvocationMessageType, Map(), "xyz"),
|
||||
binary: "kwWAo3h5eg=="),
|
||||
new ProtocolTestData(
|
||||
name: "CancelInvocationWithHeaders",
|
||||
message: AddHeaders(TestHeaders, new CancelInvocationMessage(invocationId: "xyz")),
|
||||
encoded: Array(HubProtocolConstants.CancelInvocationMessageType, TestHeadersSerialized, "xyz"),
|
||||
binary: "kwWDo0Zvb6NCYXKyS2V5V2l0aApOZXcNCkxpbmVzq1N0aWxsIFdvcmtzsVZhbHVlV2l0aE5ld0xpbmVzsEFsc28KV29ya3MNCkZpbmWjeHl6"),
|
||||
|
||||
// Ping Messages
|
||||
new ProtocolTestData(
|
||||
name: "Ping",
|
||||
message: PingMessage.Instance,
|
||||
encoded: Array(HubProtocolConstants.PingMessageType),
|
||||
binary: "kQY="),
|
||||
}.ToDictionary(t => t.Name);
|
||||
|
||||
|
|
@ -282,14 +244,11 @@ namespace Microsoft.AspNetCore.SignalR.Common.Tests.Internal.Protocol
|
|||
|
||||
// Verify that the input binary string decodes to the expected MsgPack primitives
|
||||
var bytes = Convert.FromBase64String(testData.Binary);
|
||||
var obj = Unpack(bytes);
|
||||
Assert.Equal(testData.Encoded, obj);
|
||||
|
||||
// Parse the input fully now.
|
||||
bytes = Frame(bytes);
|
||||
var protocol = new MessagePackHubProtocol();
|
||||
var data = new ReadOnlySequence<byte>(bytes);
|
||||
Assert.True(protocol.TryParseMessage(ref data, new TestBinder(testData.Message), out var message));
|
||||
Assert.True(_hubProtocol.TryParseMessage(ref data, new TestBinder(testData.Message), out var message));
|
||||
|
||||
Assert.NotNull(message);
|
||||
Assert.Equal(testData.Message, message, TestHubMessageEqualityComparer.Instance);
|
||||
|
|
@ -299,19 +258,14 @@ namespace Microsoft.AspNetCore.SignalR.Common.Tests.Internal.Protocol
|
|||
public void ParseMessageWithExtraData()
|
||||
{
|
||||
var expectedMessage = new InvocationMessage(invocationId: "xyz", target: "method", argumentBindingException: null);
|
||||
var encodedObj = Array(HubProtocolConstants.InvocationMessageType, Map(), "xyz", "method", Array(), "ex");
|
||||
var binary = "lgGAo3h5eqZtZXRob2SQomV4";
|
||||
|
||||
// Verify that the input binary string decodes to the expected MsgPack primitives
|
||||
var bytes = Convert.FromBase64String(binary);
|
||||
var obj = Unpack(bytes);
|
||||
Assert.Equal(encodedObj, obj);
|
||||
var bytes = new byte[] { Array(6), 1, 0x80, String(3), (byte)'x', (byte)'y', (byte)'z', String(6), (byte)'m', (byte)'e', (byte)'t', (byte)'h', (byte)'o', (byte)'d', Array(0), String(2), (byte)'e', (byte)'x' };
|
||||
|
||||
// Parse the input fully now.
|
||||
bytes = Frame(bytes);
|
||||
var protocol = new MessagePackHubProtocol();
|
||||
var data = new ReadOnlySequence<byte>(bytes);
|
||||
Assert.True(protocol.TryParseMessage(ref data, new TestBinder(expectedMessage), out var message));
|
||||
Assert.True(_hubProtocol.TryParseMessage(ref data, new TestBinder(expectedMessage), out var message));
|
||||
|
||||
Assert.NotNull(message);
|
||||
Assert.Equal(expectedMessage, message, TestHubMessageEqualityComparer.Instance);
|
||||
|
|
@ -324,7 +278,6 @@ namespace Microsoft.AspNetCore.SignalR.Common.Tests.Internal.Protocol
|
|||
var testData = TestData[testDataName];
|
||||
|
||||
var bytes = Write(testData.Message);
|
||||
AssertMessages(testData.Encoded, bytes);
|
||||
|
||||
// Unframe the message to check the binary encoding
|
||||
var byteSpan = new ReadOnlySequence<byte>(bytes);
|
||||
|
|
@ -335,45 +288,94 @@ namespace Microsoft.AspNetCore.SignalR.Common.Tests.Internal.Protocol
|
|||
Assert.True(string.Equals(actual, testData.Binary, StringComparison.Ordinal), $"Binary encoding changed from{Environment.NewLine} [{testData.Binary}]{Environment.NewLine} to{Environment.NewLine} [{actual}]{Environment.NewLine}Please verify the MsgPack output and update the baseline");
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void WriteAndParseDateTimeConvertsToUTC()
|
||||
{
|
||||
var dateTime = new DateTime(2018, 4, 9);
|
||||
var writer = MemoryBufferWriter.Get();
|
||||
|
||||
try
|
||||
{
|
||||
_hubProtocol.WriteMessage(CompletionMessage.WithResult("xyz", dateTime), writer);
|
||||
var bytes = new ReadOnlySequence<byte>(writer.ToArray());
|
||||
_hubProtocol.TryParseMessage(ref bytes, new TestBinder(typeof(DateTime)), out var hubMessage);
|
||||
|
||||
var completionMessage = Assert.IsType<CompletionMessage>(hubMessage);
|
||||
|
||||
var resultDateTime = (DateTime)completionMessage.Result;
|
||||
// The messagepack Timestamp format specifies that time is stored as seconds since 1970-01-01 UTC
|
||||
// so the library has no choice but to store the time as UTC
|
||||
// https://github.com/msgpack/msgpack/blob/master/spec.md#timestamp-extension-type
|
||||
Assert.Equal(dateTime.ToUniversalTime(), resultDateTime);
|
||||
}
|
||||
finally
|
||||
{
|
||||
MemoryBufferWriter.Return(writer);
|
||||
}
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void WriteAndParseDateTimeOffset()
|
||||
{
|
||||
var dateTimeOffset = new DateTimeOffset(new DateTime(2018, 4, 9), TimeSpan.FromHours(10));
|
||||
var writer = MemoryBufferWriter.Get();
|
||||
|
||||
try
|
||||
{
|
||||
_hubProtocol.WriteMessage(CompletionMessage.WithResult("xyz", dateTimeOffset), writer);
|
||||
var bytes = new ReadOnlySequence<byte>(writer.ToArray());
|
||||
_hubProtocol.TryParseMessage(ref bytes, new TestBinder(typeof(DateTimeOffset)), out var hubMessage);
|
||||
|
||||
var completionMessage = Assert.IsType<CompletionMessage>(hubMessage);
|
||||
|
||||
var resultDateTimeOffset = (DateTimeOffset)completionMessage.Result;
|
||||
Assert.Equal(dateTimeOffset, resultDateTimeOffset);
|
||||
}
|
||||
finally
|
||||
{
|
||||
MemoryBufferWriter.Return(writer);
|
||||
}
|
||||
}
|
||||
|
||||
public static IDictionary<string, InvalidMessageData> InvalidPayloads => new[]
|
||||
{
|
||||
// Message Type
|
||||
new InvalidMessageData("MessageTypeString", Array("foo"), "Reading 'messageType' as Int32 failed."),
|
||||
new InvalidMessageData("MessageTypeString", new byte[] { 0x91, 0xa3, (byte)'f', (byte)'o', (byte)'o' }, "Reading 'messageType' as Int32 failed."),
|
||||
|
||||
// Headers
|
||||
new InvalidMessageData("HeadersNotAMap", Array(HubProtocolConstants.InvocationMessageType, "foo"), "Reading map length for 'headers' failed."),
|
||||
new InvalidMessageData("HeaderKeyInt", Array(HubProtocolConstants.InvocationMessageType, Map((42, "foo"))), "Reading 'headers[0].Key' as String failed."),
|
||||
new InvalidMessageData("HeaderValueInt", Array(HubProtocolConstants.InvocationMessageType, Map(("foo", 42))), "Reading 'headers[0].Value' as String failed."),
|
||||
new InvalidMessageData("HeaderKeyArray", Array(HubProtocolConstants.InvocationMessageType, Map(("biz", "boz"), (Array(), "foo"))), "Reading 'headers[1].Key' as String failed."),
|
||||
new InvalidMessageData("HeaderValueArray", Array(HubProtocolConstants.InvocationMessageType, Map(("biz", "boz"), ("foo", Array()))), "Reading 'headers[1].Value' as String failed."),
|
||||
new InvalidMessageData("HeadersNotAMap", new byte[] { 0x92, 1, 0xa3, (byte)'f', (byte)'o', (byte)'o' }, "Reading map length for 'headers' failed."),
|
||||
new InvalidMessageData("HeaderKeyInt", new byte[] { 0x92, 1, 0x82, 0x2a, 0xa3, (byte)'f', (byte)'o', (byte)'o' }, "Reading 'headers[0].Key' as String failed."),
|
||||
new InvalidMessageData("HeaderValueInt", new byte[] { 0x92, 1, 0x82, 0xa3, (byte)'f', (byte)'o', (byte)'o', 42 }, "Reading 'headers[0].Value' as String failed."),
|
||||
new InvalidMessageData("HeaderKeyArray", new byte[] { 0x92, 1, 0x84, 0xa3, (byte)'f', (byte)'o', (byte)'o', 0xa3, (byte)'f', (byte)'o', (byte)'o', 0x90, 0xa3, (byte)'f', (byte)'o', (byte)'o' }, "Reading 'headers[1].Key' as String failed."),
|
||||
new InvalidMessageData("HeaderValueArray", new byte[] { 0x92, 1, 0x84, 0xa3, (byte)'f', (byte)'o', (byte)'o', 0xa3, (byte)'f', (byte)'o', (byte)'o', 0xa3, (byte)'f', (byte)'o', (byte)'o', 0x90 }, "Reading 'headers[1].Value' as String failed."),
|
||||
|
||||
// InvocationMessage
|
||||
new InvalidMessageData("InvocationMissingId", Array(HubProtocolConstants.InvocationMessageType, Map()), "Reading 'invocationId' as String failed."),
|
||||
new InvalidMessageData("InvocationIdBoolean", Array(HubProtocolConstants.InvocationMessageType, Map(), false), "Reading 'invocationId' as String failed."),
|
||||
new InvalidMessageData("InvocationTargetMissing", Array(HubProtocolConstants.InvocationMessageType, Map(), "abc"), "Reading 'target' as String failed."),
|
||||
new InvalidMessageData("InvocationTargetInt", Array(HubProtocolConstants.InvocationMessageType, Map(), "abc", 42), "Reading 'target' as String failed."),
|
||||
new InvalidMessageData("InvocationMissingId", new byte[] { 0x92, 1, 0x80 }, "Reading 'invocationId' as String failed."),
|
||||
new InvalidMessageData("InvocationIdBoolean", new byte[] { 0x91, 1, 0x80, 0xc2 }, "Reading 'invocationId' as String failed."),
|
||||
new InvalidMessageData("InvocationTargetMissing", new byte[] { 0x93, 1, 0x80, 0xa3, (byte)'a', (byte)'b', (byte)'c' }, "Reading 'target' as String failed."),
|
||||
new InvalidMessageData("InvocationTargetInt", new byte[] { 0x94, 1, 0x80, 0xa3, (byte)'a', (byte)'b', (byte)'c', 42 }, "Reading 'target' as String failed."),
|
||||
|
||||
// StreamInvocationMessage
|
||||
new InvalidMessageData("StreamInvocationMissingId", Array(HubProtocolConstants.StreamInvocationMessageType, Map()), "Reading 'invocationId' as String failed."),
|
||||
new InvalidMessageData("StreamInvocationIdBoolean", Array(HubProtocolConstants.StreamInvocationMessageType, Map(), false), "Reading 'invocationId' as String failed."),
|
||||
new InvalidMessageData("StreamInvocationTargetMissing", Array(HubProtocolConstants.StreamInvocationMessageType, Map(), "abc"), "Reading 'target' as String failed."),
|
||||
new InvalidMessageData("StreamInvocationTargetInt", Array(HubProtocolConstants.StreamInvocationMessageType, Map(), "abc", 42), "Reading 'target' as String failed."),
|
||||
new InvalidMessageData("StreamInvocationMissingId", new byte[] { 0x92, 4, 0x80 }, "Reading 'invocationId' as String failed."),
|
||||
new InvalidMessageData("StreamInvocationIdBoolean", new byte[] { 0x93, 4, 0x80, 0xc2 }, "Reading 'invocationId' as String failed."),
|
||||
new InvalidMessageData("StreamInvocationTargetMissing", new byte[] { 0x93, 4, 0x80, 0xa3, (byte)'a', (byte)'b', (byte)'c' }, "Reading 'target' as String failed."),
|
||||
new InvalidMessageData("StreamInvocationTargetInt", new byte[] { 0x94, 4, 0x80, 0xa3, (byte)'a', (byte)'b', (byte)'c', 42 }, "Reading 'target' as String failed."),
|
||||
|
||||
// StreamItemMessage
|
||||
new InvalidMessageData("StreamItemMissingId", Array(HubProtocolConstants.StreamItemMessageType, Map()), "Reading 'invocationId' as String failed."),
|
||||
new InvalidMessageData("StreamItemInvocationIdBoolean", Array(HubProtocolConstants.StreamItemMessageType, Map(), false), "Reading 'invocationId' as String failed."),
|
||||
new InvalidMessageData("StreamItemMissing", Array(HubProtocolConstants.StreamItemMessageType, Map(), "xyz"), "Deserializing object of the `String` type for 'item' failed."),
|
||||
new InvalidMessageData("StreamItemTypeMismatch", Array(HubProtocolConstants.StreamItemMessageType, Map(), "xyz", 42), "Deserializing object of the `String` type for 'item' failed."),
|
||||
new InvalidMessageData("StreamItemMissingId", new byte[] { 0x92, 2, 0x80 }, "Reading 'invocationId' as String failed."),
|
||||
new InvalidMessageData("StreamItemInvocationIdBoolean", new byte[] { 0x93, 2, 0x80, 0xc2 }, "Reading 'invocationId' as String failed."),
|
||||
new InvalidMessageData("StreamItemMissing", new byte[] { 0x93, 2, 0x80, 0xa3, (byte)'x', (byte)'y', (byte)'z' }, "Deserializing object of the `String` type for 'item' failed."),
|
||||
new InvalidMessageData("StreamItemTypeMismatch", new byte[] { 0x94, 2, 0x80, 0xa3, (byte)'x', (byte)'y', (byte)'z', 42 }, "Deserializing object of the `String` type for 'item' failed."),
|
||||
|
||||
// CompletionMessage
|
||||
new InvalidMessageData("CompletionMissingId", Array(HubProtocolConstants.CompletionMessageType, Map()), "Reading 'invocationId' as String failed."),
|
||||
new InvalidMessageData("CompletionIdBoolean", Array(HubProtocolConstants.CompletionMessageType, Map(), false), "Reading 'invocationId' as String failed."),
|
||||
new InvalidMessageData("CompletionResultKindString", Array(HubProtocolConstants.CompletionMessageType, Map(), "xyz", "abc"), "Reading 'resultKind' as Int32 failed."),
|
||||
new InvalidMessageData("CompletionResultKindOutOfRange", Array(HubProtocolConstants.CompletionMessageType, Map(), "xyz", 42), "Invalid invocation result kind."),
|
||||
new InvalidMessageData("CompletionErrorMissing", Array(HubProtocolConstants.CompletionMessageType, Map(), "xyz", 1), "Reading 'error' as String failed."),
|
||||
new InvalidMessageData("CompletionErrorInt", Array(HubProtocolConstants.CompletionMessageType, Map(), "xyz", 1, 42), "Reading 'error' as String failed."),
|
||||
new InvalidMessageData("CompletionResultMissing", Array(HubProtocolConstants.CompletionMessageType, Map(), "xyz", 3), "Deserializing object of the `String` type for 'argument' failed."),
|
||||
new InvalidMessageData("CompletionResultTypeMismatch", Array(HubProtocolConstants.CompletionMessageType, Map(), "xyz", 3, 42), "Deserializing object of the `String` type for 'argument' failed."),
|
||||
new InvalidMessageData("CompletionMissingId", new byte[] { 0x92, 3, 0x80 }, "Reading 'invocationId' as String failed."),
|
||||
new InvalidMessageData("CompletionIdBoolean", new byte[] { 0x93, 3, 0x80, 0xc2 }, "Reading 'invocationId' as String failed."),
|
||||
new InvalidMessageData("CompletionResultKindString", new byte[] { 0x94, 3, 0x80, 0xa3, (byte)'x', (byte)'y', (byte)'z', 0xa3, (byte)'x', (byte)'y', (byte)'z' }, "Reading 'resultKind' as Int32 failed."),
|
||||
new InvalidMessageData("CompletionResultKindOutOfRange", new byte[] { 0x94, 3, 0x80, 0xa3, (byte)'x', (byte)'y', (byte)'z', 42 }, "Invalid invocation result kind."),
|
||||
new InvalidMessageData("CompletionErrorMissing", new byte[] { 0x94, 3, 0x80, 0xa3, (byte)'x', (byte)'y', (byte)'z', 0x01 }, "Reading 'error' as String failed."),
|
||||
new InvalidMessageData("CompletionErrorInt", new byte[] { 0x95, 3, 0x80, 0xa3, (byte)'x', (byte)'y', (byte)'z', 0x01, 42 }, "Reading 'error' as String failed."),
|
||||
new InvalidMessageData("CompletionResultMissing", new byte[] { 0x94, 3, 0x80, 0xa3, (byte)'x', (byte)'y', (byte)'z', 0x03 }, "Deserializing object of the `String` type for 'argument' failed."),
|
||||
new InvalidMessageData("CompletionResultTypeMismatch", new byte[] { 0x95, 3, 0x80, 0xa3, (byte)'x', (byte)'y', (byte)'z', 0x03, 42 }, "Deserializing object of the `String` type for 'argument' failed."),
|
||||
}.ToDictionary(t => t.Name);
|
||||
|
||||
public static IEnumerable<object[]> InvalidPayloadNames => InvalidPayloads.Keys.Select(name => new object[] { name });
|
||||
|
|
@ -384,7 +386,7 @@ namespace Microsoft.AspNetCore.SignalR.Common.Tests.Internal.Protocol
|
|||
{
|
||||
var testData = InvalidPayloads[invalidPayloadName];
|
||||
|
||||
var buffer = Frame(Pack(testData.Encoded));
|
||||
var buffer = Frame(testData.Encoded);
|
||||
var binder = new TestBinder(new[] { typeof(string) }, typeof(string));
|
||||
var data = new ReadOnlySequence<byte>(buffer);
|
||||
var exception = Assert.Throws<InvalidDataException>(() => _hubProtocol.TryParseMessage(ref data, binder, out _));
|
||||
|
|
@ -395,18 +397,18 @@ namespace Microsoft.AspNetCore.SignalR.Common.Tests.Internal.Protocol
|
|||
public static IDictionary<string, InvalidMessageData> ArgumentBindingErrors => new[]
|
||||
{
|
||||
// InvocationMessage
|
||||
new InvalidMessageData("InvocationArgumentArrayMissing", Array(HubProtocolConstants.InvocationMessageType, Map(), "abc", "xyz"), "Reading array length for 'arguments' failed."),
|
||||
new InvalidMessageData("InvocationArgumentArrayNotAnArray", Array(HubProtocolConstants.InvocationMessageType, Map(), "abc", "xyz", 42), "Reading array length for 'arguments' failed."),
|
||||
new InvalidMessageData("InvocationArgumentArraySizeMismatchEmpty", Array(HubProtocolConstants.InvocationMessageType, Map(), "abc", "xyz", Array()), "Invocation provides 0 argument(s) but target expects 1."),
|
||||
new InvalidMessageData("InvocationArgumentArraySizeMismatchTooLarge", Array(HubProtocolConstants.InvocationMessageType, Map(), "abc", "xyz", Array("a", "b")), "Invocation provides 2 argument(s) but target expects 1."),
|
||||
new InvalidMessageData("InvocationArgumentTypeMismatch", Array(HubProtocolConstants.InvocationMessageType, Map(), "abc", "xyz", Array(42)), "Error binding arguments. Make sure that the types of the provided values match the types of the hub method being invoked."),
|
||||
new InvalidMessageData("InvocationArgumentArrayMissing", new byte[] { 0x94, 1, 0x80, 0xa3, (byte)'a', (byte)'b', (byte)'c', 0xa3, (byte)'x', (byte)'y', (byte)'z' }, "Reading array length for 'arguments' failed."),
|
||||
new InvalidMessageData("InvocationArgumentArrayNotAnArray", new byte[] { 0x95, 1, 0x80, 0xa3, (byte)'a', (byte)'b', (byte)'c', 0xa3, (byte)'x', (byte)'y', (byte)'z', 42 }, "Reading array length for 'arguments' failed."),
|
||||
new InvalidMessageData("InvocationArgumentArraySizeMismatchEmpty", new byte[] { 0x95, 1, 0x80, 0xa3, (byte)'a', (byte)'b', (byte)'c', 0xa3, (byte)'x', (byte)'y', (byte)'z', 0x90 }, "Invocation provides 0 argument(s) but target expects 1."),
|
||||
new InvalidMessageData("InvocationArgumentArraySizeMismatchTooLarge", new byte[] { 0x95, 1, 0x80, 0xa3, (byte)'a', (byte)'b', (byte)'c', 0xa3, (byte)'x', (byte)'y', (byte)'z', 0x92, 0xa1, (byte)'a', 0xa1, (byte)'b' }, "Invocation provides 2 argument(s) but target expects 1."),
|
||||
new InvalidMessageData("InvocationArgumentTypeMismatch", new byte[] { 0x95, 1, 0x80, 0xa3, (byte)'a', (byte)'b', (byte)'c', 0xa3, (byte)'x', (byte)'y', (byte)'z', 0x91, 42 }, "Error binding arguments. Make sure that the types of the provided values match the types of the hub method being invoked."),
|
||||
|
||||
// StreamInvocationMessage
|
||||
new InvalidMessageData("StreamInvocationArgumentArrayMissing", Array(HubProtocolConstants.StreamInvocationMessageType, Map(), "abc", "xyz"), "Reading array length for 'arguments' failed."), // array is missing
|
||||
new InvalidMessageData("StreamInvocationArgumentArrayNotAnArray", Array(HubProtocolConstants.StreamInvocationMessageType, Map(), "abc", "xyz", 42), "Reading array length for 'arguments' failed."), // arguments isn't an array
|
||||
new InvalidMessageData("StreamInvocationArgumentArraySizeMismatchEmpty", Array(HubProtocolConstants.StreamInvocationMessageType, Map(), "abc", "xyz", Array()), "Invocation provides 0 argument(s) but target expects 1."), // array is missing elements
|
||||
new InvalidMessageData("StreamInvocationArgumentArraySizeMismatchTooLarge", Array(HubProtocolConstants.StreamInvocationMessageType, Map(), "abc", "xyz", Array("a", "b")), "Invocation provides 2 argument(s) but target expects 1."), // argument count does not match binder argument count
|
||||
new InvalidMessageData("StreamInvocationArgumentTypeMismatch", Array(HubProtocolConstants.StreamInvocationMessageType, Map(), "abc", "xyz", Array(42)), "Error binding arguments. Make sure that the types of the provided values match the types of the hub method being invoked."), // argument type mismatch
|
||||
new InvalidMessageData("StreamInvocationArgumentArrayMissing", new byte[] { 0x94, 4, 0x80, 0xa3, (byte)'a', (byte)'b', (byte)'c', 0xa3, (byte)'x', (byte)'y', (byte)'z' }, "Reading array length for 'arguments' failed."), // array is missing
|
||||
new InvalidMessageData("StreamInvocationArgumentArrayNotAnArray", new byte[] { 0x95, 4, 0x80, 0xa3, (byte)'a', (byte)'b', (byte)'c', 0xa3, (byte)'x', (byte)'y', (byte)'z', 42 }, "Reading array length for 'arguments' failed."), // arguments isn't an array
|
||||
new InvalidMessageData("StreamInvocationArgumentArraySizeMismatchEmpty", new byte[] { 0x95, 4, 0x80, 0xa3, (byte)'a', (byte)'b', (byte)'c', 0xa3, (byte)'x', (byte)'y', (byte)'z', 0x90 }, "Invocation provides 0 argument(s) but target expects 1."), // array is missing elements
|
||||
new InvalidMessageData("StreamInvocationArgumentArraySizeMismatchTooLarge", new byte[] { 0x95, 4, 0x80, 0xa3, (byte)'a', (byte)'b', (byte)'c', 0xa3, (byte)'x', (byte)'y', (byte)'z', 0x92, 0xa1, (byte)'a', 0xa1, (byte)'b' }, "Invocation provides 2 argument(s) but target expects 1."), // argument count does not match binder argument count
|
||||
new InvalidMessageData("StreamInvocationArgumentTypeMismatch", new byte[] { 0x95, 4, 0x80, 0xa3, (byte)'a', (byte)'b', (byte)'c', 0xa3, (byte)'x', (byte)'y', (byte)'z', 0x91, 42 }, "Error binding arguments. Make sure that the types of the provided values match the types of the hub method being invoked."), // argument type mismatch
|
||||
}.ToDictionary(t => t.Name);
|
||||
|
||||
public static IEnumerable<object[]> ArgumentBindingErrorNames => ArgumentBindingErrors.Keys.Select(name => new object[] { name });
|
||||
|
|
@ -417,7 +419,7 @@ namespace Microsoft.AspNetCore.SignalR.Common.Tests.Internal.Protocol
|
|||
{
|
||||
var testData = ArgumentBindingErrors[argumentBindingErrorName];
|
||||
|
||||
var buffer = Frame(Pack(testData.Encoded));
|
||||
var buffer = Frame(testData.Encoded);
|
||||
var binder = new TestBinder(new[] { typeof(string) }, typeof(string));
|
||||
var data = new ReadOnlySequence<byte>(buffer);
|
||||
_hubProtocol.TryParseMessage(ref data, binder, out var message);
|
||||
|
|
@ -440,15 +442,28 @@ namespace Microsoft.AspNetCore.SignalR.Common.Tests.Internal.Protocol
|
|||
public void SerializerCanSerializeTypesWithNoDefaultCtor()
|
||||
{
|
||||
var result = Write(CompletionMessage.WithResult("0", new List<int> { 42 }.AsReadOnly()));
|
||||
AssertMessages(Array(HubProtocolConstants.CompletionMessageType, Map(), "0", 3, Array(42)), result);
|
||||
AssertMessages(new byte[] { Array(5), 3, 0x80, String(1), (byte)'0', 0x03, Array(1), 42 }, result);
|
||||
}
|
||||
|
||||
private static void AssertMessages(MessagePackObject expectedOutput, byte[] bytes)
|
||||
private byte Array(int size)
|
||||
{
|
||||
Debug.Assert(size < 16, "Test code doesn't support array sizes greater than 15");
|
||||
|
||||
return (byte)(0x90 | size);
|
||||
}
|
||||
|
||||
private byte String(int size)
|
||||
{
|
||||
Debug.Assert(size < 16, "Test code doesn't support string sizes greater than 15");
|
||||
|
||||
return (byte)(0xa0 | size);
|
||||
}
|
||||
|
||||
private static void AssertMessages(byte[] expectedOutput, ReadOnlyMemory<byte> bytes)
|
||||
{
|
||||
var data = new ReadOnlySequence<byte>(bytes);
|
||||
Assert.True(BinaryMessageParser.TryParseMessage(ref data, out var message));
|
||||
var obj = Unpack(message.ToArray());
|
||||
Assert.Equal(expectedOutput, obj);
|
||||
Assert.Equal(expectedOutput, message.ToArray());
|
||||
}
|
||||
|
||||
private static byte[] Frame(byte[] input)
|
||||
|
|
@ -466,44 +481,12 @@ namespace Microsoft.AspNetCore.SignalR.Common.Tests.Internal.Protocol
|
|||
}
|
||||
}
|
||||
|
||||
private static MessagePackObject Unpack(byte[] input)
|
||||
{
|
||||
using (var stream = new MemoryStream(input))
|
||||
{
|
||||
using (var unpacker = Unpacker.Create(stream))
|
||||
{
|
||||
Assert.True(unpacker.ReadObject(out var obj));
|
||||
return obj;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static byte[] Pack(MessagePackObject input)
|
||||
{
|
||||
var options = new PackingOptions()
|
||||
{
|
||||
StringEncoding = Encoding.UTF8
|
||||
};
|
||||
|
||||
using (var stream = new MemoryStream())
|
||||
{
|
||||
using (var packer = Packer.Create(stream))
|
||||
{
|
||||
input.PackToMessage(packer, options);
|
||||
packer.Flush();
|
||||
}
|
||||
stream.Flush();
|
||||
return stream.ToArray();
|
||||
}
|
||||
}
|
||||
|
||||
private static byte[] Write(HubMessage message)
|
||||
{
|
||||
var protocol = new MessagePackHubProtocol();
|
||||
var writer = MemoryBufferWriter.Get();
|
||||
try
|
||||
{
|
||||
protocol.WriteMessage(message, writer);
|
||||
_hubProtocol.WriteMessage(message, writer);
|
||||
return writer.ToArray();
|
||||
}
|
||||
finally
|
||||
|
|
@ -515,10 +498,10 @@ namespace Microsoft.AspNetCore.SignalR.Common.Tests.Internal.Protocol
|
|||
public class InvalidMessageData
|
||||
{
|
||||
public string Name { get; private set; }
|
||||
public MessagePackObject Encoded { get; private set; }
|
||||
public byte[] Encoded { get; private set; }
|
||||
public string ErrorMessage { get; private set; }
|
||||
|
||||
public InvalidMessageData(string name, MessagePackObject encoded, string errorMessage)
|
||||
public InvalidMessageData(string name, byte[] encoded, string errorMessage)
|
||||
{
|
||||
Name = name;
|
||||
Encoded = encoded;
|
||||
|
|
@ -532,14 +515,12 @@ namespace Microsoft.AspNetCore.SignalR.Common.Tests.Internal.Protocol
|
|||
{
|
||||
public string Name { get; }
|
||||
public string Binary { get; }
|
||||
public MessagePackObject Encoded { get; }
|
||||
public HubMessage Message { get; }
|
||||
|
||||
public ProtocolTestData(string name, HubMessage message, MessagePackObject encoded, string binary)
|
||||
public ProtocolTestData(string name, HubMessage message, string binary)
|
||||
{
|
||||
Name = name;
|
||||
Message = message;
|
||||
Encoded = encoded;
|
||||
Binary = binary;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -11,7 +11,6 @@ using Microsoft.AspNetCore.SignalR.Tests;
|
|||
using Microsoft.Extensions.Logging.Abstractions;
|
||||
using Microsoft.Extensions.Options;
|
||||
using Moq;
|
||||
using MsgPack.Serialization;
|
||||
using Newtonsoft.Json.Linq;
|
||||
using Newtonsoft.Json.Serialization;
|
||||
using Xunit;
|
||||
|
|
@ -506,7 +505,6 @@ namespace Microsoft.AspNetCore.SignalR.Redis.Tests
|
|||
var server = new TestRedisServer();
|
||||
|
||||
var messagePackOptions = new MessagePackHubProtocolOptions();
|
||||
messagePackOptions.SerializationContext.DictionarySerlaizationOptions.KeyTransformer = DictionaryKeyTransformers.LowerCamel;
|
||||
|
||||
var jsonOptions = new JsonHubProtocolOptions();
|
||||
jsonOptions.PayloadSerializerSettings.ContractResolver = new CamelCasePropertyNamesContractResolver();
|
||||
|
|
|
|||
|
|
@ -8,6 +8,8 @@ using System.Linq;
|
|||
using System.Security.Claims;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using MessagePack;
|
||||
using MessagePack.Formatters;
|
||||
using Microsoft.AspNetCore.Connections;
|
||||
using Microsoft.AspNetCore.Http;
|
||||
using Microsoft.AspNetCore.Http.Connections;
|
||||
|
|
@ -16,8 +18,6 @@ using Microsoft.AspNetCore.SignalR.Internal.Protocol;
|
|||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Microsoft.Extensions.Options;
|
||||
using Moq;
|
||||
using MsgPack;
|
||||
using MsgPack.Serialization;
|
||||
using Newtonsoft.Json;
|
||||
using Newtonsoft.Json.Linq;
|
||||
using Newtonsoft.Json.Serialization;
|
||||
|
|
@ -1679,7 +1679,7 @@ namespace Microsoft.AspNetCore.SignalR.Tests
|
|||
services.AddSignalR()
|
||||
.AddMessagePackProtocol(options =>
|
||||
{
|
||||
options.SerializationContext.SerializationMethod = SerializationMethod.Array;
|
||||
options.FormatterResolvers.Insert(0, new CustomFormatter());
|
||||
});
|
||||
});
|
||||
|
||||
|
|
@ -1697,10 +1697,9 @@ namespace Microsoft.AspNetCore.SignalR.Tests
|
|||
|
||||
var message = Assert.IsType<InvocationMessage>(await client.ReadAsync().OrTimeout());
|
||||
|
||||
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()));
|
||||
var result = message.Arguments[0] as Dictionary<object, object>;
|
||||
Assert.Equal("formattedString", result["Message"]);
|
||||
Assert.Equal("formattedString", result["paramName"]);
|
||||
|
||||
client.Dispose();
|
||||
|
||||
|
|
@ -1708,6 +1707,50 @@ namespace Microsoft.AspNetCore.SignalR.Tests
|
|||
}
|
||||
}
|
||||
|
||||
private class CustomFormatter : IFormatterResolver
|
||||
{
|
||||
public IMessagePackFormatter<T> GetFormatter<T>()
|
||||
{
|
||||
if (typeof(T) == typeof(string))
|
||||
{
|
||||
return new StringFormatter<T>();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private class StringFormatter<T> : IMessagePackFormatter<T>
|
||||
{
|
||||
public T Deserialize(byte[] bytes, int offset, IFormatterResolver formatterResolver, out int readSize)
|
||||
{
|
||||
// this method isn't used in our tests
|
||||
readSize = 0;
|
||||
return default;
|
||||
}
|
||||
|
||||
public int Serialize(ref byte[] bytes, int offset, T value, IFormatterResolver formatterResolver)
|
||||
{
|
||||
// string of size 15
|
||||
bytes[offset] = 0xAF;
|
||||
bytes[offset + 1] = (byte)'f';
|
||||
bytes[offset + 2] = (byte)'o';
|
||||
bytes[offset + 3] = (byte)'r';
|
||||
bytes[offset + 4] = (byte)'m';
|
||||
bytes[offset + 5] = (byte)'a';
|
||||
bytes[offset + 6] = (byte)'t';
|
||||
bytes[offset + 7] = (byte)'t';
|
||||
bytes[offset + 8] = (byte)'e';
|
||||
bytes[offset + 9] = (byte)'d';
|
||||
bytes[offset + 10] = (byte)'S';
|
||||
bytes[offset + 11] = (byte)'t';
|
||||
bytes[offset + 12] = (byte)'r';
|
||||
bytes[offset + 13] = (byte)'i';
|
||||
bytes[offset + 14] = (byte)'n';
|
||||
bytes[offset + 15] = (byte)'g';
|
||||
return 16;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task CanGetHttpContextFromHubConnectionContext()
|
||||
{
|
||||
|
|
|
|||
Loading…
Reference in New Issue