diff --git a/client-ts/Microsoft.AspNetCore.SignalR.Client.TS.Tests/Formatters.spec.ts b/client-ts/Microsoft.AspNetCore.SignalR.Client.TS.Tests/Formatters.spec.ts index 9c7501461f..dbd43c19a1 100644 --- a/client-ts/Microsoft.AspNetCore.SignalR.Client.TS.Tests/Formatters.spec.ts +++ b/client-ts/Microsoft.AspNetCore.SignalR.Client.TS.Tests/Formatters.spec.ts @@ -1,4 +1,4 @@ -import { TextMessageFormat } from "../Microsoft.AspNetCore.SignalR.Client.TS/Formatters" +import { TextMessageFormat, BinaryMessageFormat } from "../Microsoft.AspNetCore.SignalR.Client.TS/Formatters" describe("Text Message Formatter", () => { it("should return empty array on empty input", () => { @@ -30,3 +30,43 @@ describe("Text Message Formatter", () => { }); }); }); + +describe("Binary Message Formatter", () => { + ([ + [[0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00], [ new Uint8Array([])]], + [[0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0xff], [ new Uint8Array([0xff])]], + [[0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0xff, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x7f], [ new Uint8Array([0xff]), new Uint8Array([0x7f])]], + ] as [[number[], Uint8Array[]]]).forEach(([payload, expected_messages]) => { + it(`should parse '${payload}' correctly`, () => { + let messages = BinaryMessageFormat.parse(new Uint8Array(payload).buffer); + expect(messages).toEqual(expected_messages); + }) + }); + + ([ + [[0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00], new Error("Cannot read message size")], + [[0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x01, 0x80, 0x00], new Error("Cannot read message size")], + [[0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00], new Error("Messages bigger than 2147483647 bytes are not supported")], + [[0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00], new Error("Messages bigger than 2147483647 bytes are not supported")], + [[0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00], new Error("Messages bigger than 2147483647 bytes are not supported")], + [[0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00], new Error("Messages bigger than 2147483647 bytes are not supported")], + [[0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00], new Error("Messages bigger than 2147483647 bytes are not supported")], + [[0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00], new Error("Incomplete message")], + ] as [[number[], Error]]).forEach(([payload, expected_error]) => { + it(`should fail to parse '${payload}'`, () => { + expect(() => BinaryMessageFormat.parse(new Uint8Array(payload).buffer)).toThrow(expected_error); + }) + }); + + ([ + [[], [0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]], + [[0x20], [0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x20]], + ] as [[number[], number[]]]).forEach(([input, expected_payload]) => { + it(`should write '${input}'`, () => { + let actual = new Uint8Array(BinaryMessageFormat.write(new Uint8Array(input))); + let expected = new Uint8Array(expected_payload); + expect(actual).toEqual(expected); + }) + }); +}); diff --git a/client-ts/Microsoft.AspNetCore.SignalR.Client.TS.Tests/MessagePackHubProtocol.spec.ts b/client-ts/Microsoft.AspNetCore.SignalR.Client.TS.Tests/MessagePackHubProtocol.spec.ts new file mode 100644 index 0000000000..8d62a2c30a --- /dev/null +++ b/client-ts/Microsoft.AspNetCore.SignalR.Client.TS.Tests/MessagePackHubProtocol.spec.ts @@ -0,0 +1,103 @@ +import { MessagePackHubProtocol } from "../Microsoft.AspNetCore.SignalR.Client.TS/MessagePackHubProtocol" +import { MessageType, InvocationMessage, CompletionMessage, ResultMessage } from "../Microsoft.AspNetCore.SignalR.Client.TS/IHubProtocol" + +describe("MessageHubProtocol", () => { + it("can write/read Invocation message", () => { + let invocation = { + type: MessageType.Invocation, + invocationId: "123", + target: "myMethod", + nonblocking: true, + arguments: [42, true, "test", ["x1", "y2"], null] + }; + + let protocol = new MessagePackHubProtocol(); + var parsedMessages = protocol.parseMessages(protocol.writeMessage(invocation)); + expect(parsedMessages).toEqual([invocation]); + }); + + ([ + [ [ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0b, + 0x94, 0x03, 0xa3, 0x61, 0x62, 0x63, 0x01, 0xa3, 0x45, 0x72, 0x72], + { + type: MessageType.Completion, + invocationId: "abc", + error: "Err", + result: null + } as CompletionMessage ], + [ [ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0a, + 0x94, 0x03, 0xa3, 0x61, 0x62, 0x63, 0x03, 0xa2, 0x4f, 0x4b ], + { + type: MessageType.Completion, + invocationId: "abc", + error: null, + result: "OK" + } as CompletionMessage ], + [ [ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, + 0x93, 0x03, 0xa3, 0x61, 0x62, 0x63, 0x02 ], + { + type: MessageType.Completion, + invocationId: "abc", + error: null, + result: null + } as CompletionMessage ] + ] as [[number[], CompletionMessage]]).forEach(([payload, expected_message]) => + it("can read Completion message", () => { + let messages = new MessagePackHubProtocol().parseMessages(new Uint8Array(payload).buffer); + expect(messages).toEqual([expected_message]); + })); + + ([ + [ [ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, + 0x93, 0x02, 0xa3, 0x61, 0x62, 0x63, 0x08 ], + { + type: MessageType.Result, + invocationId: "abc", + item: 8 + } as ResultMessage ] + ] as [[number[], CompletionMessage]]).forEach(([payload, expected_message]) => + it("can read Result message", () => { + let messages = new MessagePackHubProtocol().parseMessages(new Uint8Array(payload).buffer); + expect(messages).toEqual([expected_message]); + })); + + ([ + [ [ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 ], new Error("Invalid payload.") ], + [ [ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x90 ], new Error("Invalid payload.") ], + [ [ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0xc2 ], new Error("Invalid payload.") ], + [ [ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x91, 0x05 ], new Error("Invalid message type.") ], + [ [ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x91, 0xa1, 0x78 ], new Error("Invalid message type.") ], + [ [ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x91, 0x01 ], new Error("Invalid payload for Invocation message.") ], + [ [ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x91, 0x02 ], new Error("Invalid payload for stream Result message.") ], + [ [ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x92, 0x03, 0xa0 ], new Error("Invalid payload for Completion message.") ], + [ [ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x94, 0x03, 0xa0, 0x02, 0x00 ], new Error("Invalid payload for Completion message.") ], + [ [ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x93, 0x03, 0xa0, 0x01 ], new Error("Invalid payload for Completion message.") ], + [ [ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x93, 0x03, 0xa0, 0x03 ], new Error("Invalid payload for Completion message.") ] + ] as [[number[], Error]]).forEach(([payload, expected_error]) => + it("throws for invalid messages", () => { + expect(() => new MessagePackHubProtocol().parseMessages(new Uint8Array(payload).buffer)) + .toThrow(expected_error); + })); + + it("can read multiple messages", () => { + let payload = [ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, + 0x93, 0x02, 0xa3, 0x61, 0x62, 0x63, 0x08, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0a, + 0x94, 0x03, 0xa3, 0x61, 0x62, 0x63, 0x03, 0xa2, 0x4f, 0x4b ]; + let messages = new MessagePackHubProtocol().parseMessages(new Uint8Array(payload).buffer); + expect(messages).toEqual([ + { + type: MessageType.Result, + invocationId: "abc", + item: 8 + } as ResultMessage, + { + type: MessageType.Completion, + invocationId: "abc", + error: null, + result: "OK" + } as CompletionMessage + ]); + }); +}); \ No newline at end of file diff --git a/client-ts/Microsoft.AspNetCore.SignalR.Client.TS/Formatters.ts b/client-ts/Microsoft.AspNetCore.SignalR.Client.TS/Formatters.ts index 4dd91b5c81..940b09f2da 100644 --- a/client-ts/Microsoft.AspNetCore.SignalR.Client.TS/Formatters.ts +++ b/client-ts/Microsoft.AspNetCore.SignalR.Client.TS/Formatters.ts @@ -34,7 +34,7 @@ export namespace TextMessageFormat { if (!hasSpace(input, offset, 1 + length)) { throw new Error("Message is incomplete"); } - + // Read the payload var payload = input.substr(offset, length); offset += length; @@ -66,4 +66,56 @@ export namespace TextMessageFormat { } return messages; } +} + +export namespace BinaryMessageFormat { + export function write(output: Uint8Array): ArrayBuffer { + let size = output.byteLength; + let buffer = new Uint8Array(size + 8); + + // javascript bitwise operators only support 32-bit integers + for (let i = 7; i >= 4; i--) { + buffer[i] = size & 0xff; + size = size >> 8; + } + + buffer.set(output, 8); + + return buffer.buffer; + } + + export function parse(input: ArrayBuffer): Uint8Array[] { + let result: Uint8Array[] = []; + let uint8Array = new Uint8Array(input); + // 8 - the length prefix size + for (let offset = 0; offset < input.byteLength;) { + + if (input.byteLength < offset + 8) { + throw new Error("Cannot read message size") + } + + // Note javascript bitwise operators only support 32-bit integers - for now cutting bigger messages. + // Tracking bug https://github.com/aspnet/SignalR/issues/613 + if (!(uint8Array[offset] == 0 && uint8Array[offset + 1] == 0 && uint8Array[offset + 2] == 0 + && uint8Array[offset + 3] == 0 && (uint8Array[offset + 4] & 0x80) == 0)) { + throw new Error("Messages bigger than 2147483647 bytes are not supported"); + } + + let size = 0; + for (let i = 4; i < 8; i++) { + size = (size << 8) | uint8Array[offset + i]; + } + + if (uint8Array.byteLength >= (offset + 8 + size)) { + result.push(uint8Array.slice(offset + 8, offset + 8 + size)) + } + else { + throw new Error("Incomplete message"); + } + + offset = offset + 8 + size; + } + + return result; + } } \ No newline at end of file diff --git a/client-ts/Microsoft.AspNetCore.SignalR.Client.TS/HubConnection.ts b/client-ts/Microsoft.AspNetCore.SignalR.Client.TS/HubConnection.ts index 06061cbfff..96164bc9d3 100644 --- a/client-ts/Microsoft.AspNetCore.SignalR.Client.TS/HubConnection.ts +++ b/client-ts/Microsoft.AspNetCore.SignalR.Client.TS/HubConnection.ts @@ -16,8 +16,9 @@ export class HubConnection { private connectionClosedCallback: ConnectionClosed; private protocol: IHubProtocol; - constructor(connection: IConnection) { + constructor(connection: IConnection, protocol: IHubProtocol = new JsonHubProtocol()) { this.connection = connection; + this.protocol = protocol || new JsonHubProtocol(); this.connection.onDataReceived = data => { this.onDataReceived(data); }; @@ -28,7 +29,6 @@ export class HubConnection { this.callbacks = new Map void>(); this.methods = new Map void>(); this.id = 0; - this.protocol = new JsonHubProtocol(); } private onDataReceived(data: any) { diff --git a/client-ts/Microsoft.AspNetCore.SignalR.Client.TS/IHubProtocol.ts b/client-ts/Microsoft.AspNetCore.SignalR.Client.TS/IHubProtocol.ts index dfe03ffe11..ff1ff3de6e 100644 --- a/client-ts/Microsoft.AspNetCore.SignalR.Client.TS/IHubProtocol.ts +++ b/client-ts/Microsoft.AspNetCore.SignalR.Client.TS/IHubProtocol.ts @@ -30,6 +30,6 @@ export interface NegotiationMessage { export interface IHubProtocol { name(): string; - parseMessages(input: string): HubMessage[]; - writeMessage(message: HubMessage): string; + parseMessages(input: any): HubMessage[]; + writeMessage(message: HubMessage): any; } \ No newline at end of file diff --git a/client-ts/Microsoft.AspNetCore.SignalR.Client.TS/MessagePackHubProtocol.ts b/client-ts/Microsoft.AspNetCore.SignalR.Client.TS/MessagePackHubProtocol.ts new file mode 100644 index 0000000000..436393135e --- /dev/null +++ b/client-ts/Microsoft.AspNetCore.SignalR.Client.TS/MessagePackHubProtocol.ts @@ -0,0 +1,117 @@ +import { IHubProtocol, MessageType, HubMessage, InvocationMessage, ResultMessage, CompletionMessage } from "./IHubProtocol"; +import { BinaryMessageFormat } from "./Formatters" + +var msgpack = require("msgpack-lite"); + +export class MessagePackHubProtocol implements IHubProtocol { + name(): string { + return "messagepack"; + } + + parseMessages(input: ArrayBuffer): HubMessage[] { + return BinaryMessageFormat.parse(input).map(m => this.parseMessage(m)); + } + + private parseMessage(input: Uint8Array): HubMessage { + if (input.length == 0) { + throw new Error("Invalid payload."); + } + + let properties = msgpack.decode(input); + if (properties.length == 0 || !(properties instanceof Array)) { + throw new Error("Invalid payload."); + } + + let messageType = properties[0] as MessageType; + switch (messageType) { + case MessageType.Invocation: + return this.createInvocationMessage(properties); + case MessageType.Result: + return this.createStreamItemMessage(properties); + case MessageType.Completion: + return this.createCompletionMessage(properties); + default: + throw new Error("Invalid message type."); + } + } + + private createInvocationMessage(properties: any[]): InvocationMessage { + if (properties.length != 5) { + throw new Error("Invalid payload for Invocation message."); + } + + return { + type: MessageType.Invocation, + invocationId: properties[1], + nonblocking: properties[2], + target: properties[3], + arguments: properties[4] + } as InvocationMessage; + } + + private createStreamItemMessage(properties: any[]): ResultMessage { + if (properties.length != 3) { + throw new Error("Invalid payload for stream Result message."); + } + + return { + type: MessageType.Result, + invocationId: properties[1], + item: properties[2] + } as ResultMessage; + } + + private createCompletionMessage(properties: any[]): CompletionMessage { + if (properties.length < 3) { + throw new Error("Invalid payload for Completion message."); + } + + const errorResult = 1; + const voidResult = 2; + const nonVoidResult = 3; + + let resultKind = properties[2]; + + if ((resultKind === voidResult && properties.length != 3) || + (resultKind !== voidResult && properties.length != 4)) { + throw new Error("Invalid payload for Completion message."); + } + + let completionMessage = { + type: MessageType.Completion, + invocationId: properties[1], + error: null as string, + result: null as any + }; + + switch (resultKind) { + case errorResult: + completionMessage.error = properties[3]; + break; + case nonVoidResult: + completionMessage.result = properties[3]; + break; + } + + return completionMessage as ResultMessage; + } + + writeMessage(message: HubMessage): ArrayBuffer { + switch (message.type) { + case MessageType.Invocation: + return this.writeInvocation(message as InvocationMessage); + case MessageType.Result: + case MessageType.Completion: + throw new Error(`Writing messages of type '${message.type}' is not supported.`); + default: + throw new Error("Invalid message type."); + } + } + + private writeInvocation(invocationMessage: InvocationMessage): ArrayBuffer { + let payload = msgpack.encode([ MessageType.Invocation, invocationMessage.invocationId, + invocationMessage.nonblocking, invocationMessage.target, invocationMessage.arguments]); + + return BinaryMessageFormat.write(payload); + } +} \ No newline at end of file diff --git a/client-ts/Microsoft.AspNetCore.SignalR.Client.TS/gulpfile.js b/client-ts/Microsoft.AspNetCore.SignalR.Client.TS/gulpfile.js index a5b47fab36..dccfb511f5 100644 --- a/client-ts/Microsoft.AspNetCore.SignalR.Client.TS/gulpfile.js +++ b/client-ts/Microsoft.AspNetCore.SignalR.Client.TS/gulpfile.js @@ -24,6 +24,7 @@ gulp.task('browserify-client', ['compile-ts-client'], () => { .pipe(gulp.dest(clientOutDir + '/../browser')); }); + gulp.task('build-ts-client', ['clean', 'compile-ts-client', 'browserify-client']); gulp.task('default', ['build-ts-client']); diff --git a/client-ts/Microsoft.AspNetCore.SignalR.Client.TS/tsconfig.json b/client-ts/Microsoft.AspNetCore.SignalR.Client.TS/tsconfig.json index 1270feff97..791e6d8226 100644 --- a/client-ts/Microsoft.AspNetCore.SignalR.Client.TS/tsconfig.json +++ b/client-ts/Microsoft.AspNetCore.SignalR.Client.TS/tsconfig.json @@ -10,7 +10,10 @@ "noImplicitAny": true, "suppressImplicitAnyIndexErrors": true, "outDir": "../dist/src", - "declaration": true + "declaration": true, + "typeRoots": [ + "../node_modules/@types" + ] }, "include": [ "./**/*", diff --git a/client-ts/Microsoft.AspNetCore.SignalR.Test.Server/wwwroot/js/hubConnectionTests.js b/client-ts/Microsoft.AspNetCore.SignalR.Test.Server/wwwroot/js/hubConnectionTests.js index 242fdf20be..5f6296d14d 100644 --- a/client-ts/Microsoft.AspNetCore.SignalR.Test.Server/wwwroot/js/hubConnectionTests.js +++ b/client-ts/Microsoft.AspNetCore.SignalR.Test.Server/wwwroot/js/hubConnectionTests.js @@ -5,7 +5,7 @@ describe('hubConnection', () => { describe(`${signalR.TransportType[transportType]} transport`, () => { it(`can invoke server method and receive result`, done => { const message = "Hi"; - let hubConnection = new signalR.HubConnection(new signalR.HttpConnection(TESTHUBENDPOINT_URL, { transport: transportType }), 'formatType=json&format=text'); + let hubConnection = new signalR.HubConnection(new signalR.HttpConnection(TESTHUBENDPOINT_URL, { transport: transportType })); hubConnection.onClosed = error => { expect(error).toBe(undefined); done(); @@ -31,7 +31,7 @@ describe('hubConnection', () => { }); it(`can stream server method and receive result`, done => { - let hubConnection = new signalR.HubConnection(new signalR.HttpConnection(TESTHUBENDPOINT_URL, { transport: transportType }), 'formatType=json&format=text'); + let hubConnection = new signalR.HubConnection(new signalR.HttpConnection(TESTHUBENDPOINT_URL, { transport: transportType })); hubConnection.onClosed = error => { expect(error).toBe(undefined); done(); @@ -63,7 +63,7 @@ describe('hubConnection', () => { it(`rethrows an exception from the server when invoking`, done => { const errorMessage = "An error occurred."; - let hubConnection = new signalR.HubConnection(new signalR.HttpConnection(TESTHUBENDPOINT_URL, { transport: transportType }), 'formatType=json&format=text'); + let hubConnection = new signalR.HubConnection(new signalR.HttpConnection(TESTHUBENDPOINT_URL, { transport: transportType })); hubConnection.start() .then(() => { @@ -90,7 +90,7 @@ describe('hubConnection', () => { it(`rethrows an exception from the server when streaming`, done => { const errorMessage = "An error occurred."; - let hubConnection = new signalR.HubConnection(new signalR.HttpConnection(TESTHUBENDPOINT_URL, { transport: transportType }), 'formatType=json&format=text'); + let hubConnection = new signalR.HubConnection(new signalR.HttpConnection(TESTHUBENDPOINT_URL, { transport: transportType })); hubConnection.start() .then(() => { @@ -116,7 +116,7 @@ describe('hubConnection', () => { }); it(`can receive server calls`, done => { - let client = new signalR.HubConnection(new signalR.HttpConnection(TESTHUBENDPOINT_URL, { transport: transportType }), 'formatType=json&format=text'); + let client = new signalR.HubConnection(new signalR.HttpConnection(TESTHUBENDPOINT_URL, { transport: transportType })); const message = "Hello SignalR"; let callbackPromise = new Promise((resolve, reject) => { @@ -150,7 +150,7 @@ describe('hubConnection', () => { ServerSentEvents: "Error occurred" }; - let hubConnection = new signalR.HubConnection(new signalR.HttpConnection(`http://${document.location.host}/uncreatable`, { transport: transportType }), 'formatType=json&format=text'); + let hubConnection = new signalR.HubConnection(new signalR.HttpConnection(`http://${document.location.host}/uncreatable`, { transport: transportType })); hubConnection.onClosed = error => { expect(error).toMatch(errorRegex[signalR.TransportType[transportType]]); diff --git a/client-ts/package.json b/client-ts/package.json index 03d269eccd..fb9506d57b 100644 --- a/client-ts/package.json +++ b/client-ts/package.json @@ -23,11 +23,13 @@ }, "homepage": "https://github.com/aspnet/SignalR#readme", "devDependencies": { + "@types/node": "^8.0.19", "browserify": "^13.1.1", "del": "^2.2.2", "gulp": "^3.9.1", "gulp-typescript": "^3.1.3", "jasmine": "^2.5.2", + "msgpack-lite": "^0.1.26", "typescript": "^2.0.10", "vinyl-source-stream": "^1.1.0" } diff --git a/src/Microsoft.AspNetCore.SignalR.Common/Internal/Protocol/MessagePackHubProtocol.cs b/src/Microsoft.AspNetCore.SignalR.Common/Internal/Protocol/MessagePackHubProtocol.cs index e8fc729f6e..9b62789983 100644 --- a/src/Microsoft.AspNetCore.SignalR.Common/Internal/Protocol/MessagePackHubProtocol.cs +++ b/src/Microsoft.AspNetCore.SignalR.Common/Internal/Protocol/MessagePackHubProtocol.cs @@ -136,7 +136,7 @@ private void WriteMessageCore(HubMessage message, Stream output) WriteInvocationMessage(invocationMessage, packer, output); break; case StreamItemMessage streamItemMessage: - WriteStremingItemMessage(streamItemMessage, packer, output); + WriteStreamingItemMessage(streamItemMessage, packer, output); break; case CompletionMessage completionMessage: WriteCompletionMessage(completionMessage, packer, output); @@ -156,7 +156,7 @@ private static void WriteInvocationMessage(InvocationMessage invocationMessage, packer.PackObject(invocationMessage.Arguments); } - private void WriteStremingItemMessage(StreamItemMessage streamItemMessage, Packer packer, Stream output) + private void WriteStreamingItemMessage(StreamItemMessage streamItemMessage, Packer packer, Stream output) { packer.PackArrayHeader(3); packer.Pack(StreamItemMessageType); @@ -171,7 +171,7 @@ private void WriteCompletionMessage(CompletionMessage completionMessage, Packer completionMessage.HasResult ? NonVoidResult : VoidResult; - packer.PackArrayHeader(2 + resultKind != VoidResult ? 1 : 0); + packer.PackArrayHeader(3 + resultKind != VoidResult ? 1 : 0); packer.Pack(CompletionMessageType); packer.PackString(completionMessage.InvocationId); packer.Pack(resultKind); diff --git a/test/Microsoft.AspNetCore.SignalR.Common.Tests/Internal/Protocol/MessagePackHubProtocolTests.cs b/test/Microsoft.AspNetCore.SignalR.Common.Tests/Internal/Protocol/MessagePackHubProtocolTests.cs index 97f3dfff89..eeccf7f75d 100644 --- a/test/Microsoft.AspNetCore.SignalR.Common.Tests/Internal/Protocol/MessagePackHubProtocolTests.cs +++ b/test/Microsoft.AspNetCore.SignalR.Common.Tests/Internal/Protocol/MessagePackHubProtocolTests.cs @@ -109,8 +109,6 @@ public void CanRoundTripInvocationMessage(HubMessage[] hubMessages) new object[] { new byte[] { 0x93, 0x03, 0xa3, 0x78, 0x79, 0x7a, 0x03 }, "Deserializing object of the `String` type for 'argument' failed." }, // non void result but result missing new object[] { new byte[] { 0x93, 0x03, 0xa3, 0x78, 0x79, 0x7a, 0x03, 0xa9 }, "Deserializing object of the `String` type for 'argument' failed." }, // result is cut new object[] { new byte[] { 0x93, 0x03, 0xa3, 0x78, 0x79, 0x7a, 0x03, 0x00 }, "Deserializing object of the `String` type for 'argument' failed." }, // return type mismatch - - // TODO: ReadAsInt32 and no int32 value }; [Theory]