diff --git a/client-ts/Microsoft.AspNetCore.SignalR.Client.TS.Tests/HubConnection.spec.ts b/client-ts/Microsoft.AspNetCore.SignalR.Client.TS.Tests/HubConnection.spec.ts index 06be069cf1..2312f5b7ee 100644 --- a/client-ts/Microsoft.AspNetCore.SignalR.Client.TS.Tests/HubConnection.spec.ts +++ b/client-ts/Microsoft.AspNetCore.SignalR.Client.TS.Tests/HubConnection.spec.ts @@ -391,6 +391,40 @@ describe("HubConnection", () => { expect(await observer.completed).toEqual([1, 2, 3]); }); }); + + describe("onClose", () => { + it("it can have multiple callbacks", async () => { + let connection = new TestConnection(); + let hubConnection = new HubConnection(connection); + let invocations = 0; + hubConnection.onClosed(e => invocations++); + hubConnection.onClosed(e => invocations++); + // Typically this would be called by the transport + connection.onClosed(); + expect(invocations).toBe(2); + }); + + it("callbacks receive error", async () => { + let connection = new TestConnection(); + let hubConnection = new HubConnection(connection); + let error: Error; + hubConnection.onClosed(e => error = e); + + // Typically this would be called by the transport + connection.onClosed(new Error("Test error.")); + expect(error.message).toBe("Test error."); + }); + + it("ignores null callbacks", async () => { + let connection = new TestConnection(); + let hubConnection = new HubConnection(connection); + hubConnection.onClosed(null); + hubConnection.onClosed(undefined); + // Typically this would be called by the transport + connection.onClosed(); + // expect no errors + }); + }); }); class TestConnection implements IConnection { diff --git a/client-ts/Microsoft.AspNetCore.SignalR.Client.TS/HubConnection.ts b/client-ts/Microsoft.AspNetCore.SignalR.Client.TS/HubConnection.ts index f59bce05a2..4de459ad52 100644 --- a/client-ts/Microsoft.AspNetCore.SignalR.Client.TS/HubConnection.ts +++ b/client-ts/Microsoft.AspNetCore.SignalR.Client.TS/HubConnection.ts @@ -27,7 +27,7 @@ export class HubConnection { private callbacks: Map void>; private methods: Map void)[]>; private id: number; - private connectionClosedCallback: ConnectionClosed; + private closedCallbacks: ConnectionClosed[]; constructor(urlOrConnection: string | IConnection, options: IHubConnectionOptions = {}) { options = options || {}; @@ -44,12 +44,13 @@ export class HubConnection { this.connection.onDataReceived = data => { this.onDataReceived(data); }; - this.connection.onClosed = (error: Error) => { + this.connection.onClosed = (error?: Error) => { this.onConnectionClosed(error); } this.callbacks = new Map void>(); this.methods = new Map void)[]>(); + this.closedCallbacks = []; this.id = 0; } @@ -94,7 +95,7 @@ export class HubConnection { } } - private onConnectionClosed(error: Error) { + private onConnectionClosed(error?: Error) { let errorCompletionMessage = { type: MessageType.Completion, invocationId: "-1", @@ -106,9 +107,7 @@ export class HubConnection { }); this.callbacks.clear(); - if (this.connectionClosedCallback) { - this.connectionClosedCallback(error); - } + this.closedCallbacks.forEach(c => c.apply(this, [error])); } async start(): Promise { @@ -239,8 +238,10 @@ export class HubConnection { } } - set onClosed(callback: ConnectionClosed) { - this.connectionClosedCallback = callback; + onClosed(callback: ConnectionClosed) { + if (callback) { + this.closedCallbacks.push(callback); + } } private createInvocation(methodName: string, args: any[], nonblocking: boolean): InvocationMessage { 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 39e45f09aa..49be37c86c 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 @@ -18,10 +18,10 @@ describe('hubConnection', function () { logging: signalR.LogLevel.Trace }; var hubConnection = new signalR.HubConnection(TESTHUBENDPOINT_URL, options); - hubConnection.onClosed = function (error) { + hubConnection.onClosed(function (error) { expect(error).toBe(undefined); done(); - }; + }); hubConnection.start().then(function () { hubConnection.invoke('Echo', message).then(function (result) { @@ -46,10 +46,10 @@ describe('hubConnection', function () { }; var hubConnection = new signalR.HubConnection(TESTHUBENDPOINT_URL, options); - hubConnection.onClosed = function (error) { + hubConnection.onClosed(function (error) { expect(error).toBe(undefined); done(); - }; + }); var received = []; hubConnection.start().then(function () { @@ -172,10 +172,10 @@ describe('hubConnection', function () { }; var hubConnection = new signalR.HubConnection('http://' + document.location.host + '/uncreatable', options); - hubConnection.onClosed = function (error) { + hubConnection.onClosed(function (error) { expect(error.message).toMatch(errorRegex[signalR.TransportType[transportType]]); done(); - }; + }); hubConnection.start(); }); });