From 306a95cd0425f6fd8ca15cde30720d9229edd6b0 Mon Sep 17 00:00:00 2001 From: z77ma <vlad.krb@gmail.com> Date: Mon, 24 Jan 2022 18:27:30 +0100 Subject: [PATCH] Fix: The next event handler is not called if the previous event handler removes itself (#39716) --- .../clients/ts/signalr/src/HubConnection.ts | 3 +- .../ts/signalr/tests/HubConnection.test.ts | 46 +++++++++++++++++++ 2 files changed, 48 insertions(+), 1 deletion(-) diff --git a/src/SignalR/clients/ts/signalr/src/HubConnection.ts b/src/SignalR/clients/ts/signalr/src/HubConnection.ts index 3f1363374c7..aaaf27d8c0d 100644 --- a/src/SignalR/clients/ts/signalr/src/HubConnection.ts +++ b/src/SignalR/clients/ts/signalr/src/HubConnection.ts @@ -674,8 +674,9 @@ export class HubConnection { private _invokeClientMethod(invocationMessage: InvocationMessage) { const methods = this._methods[invocationMessage.target.toLowerCase()]; if (methods) { + const methodsCopy = methods.slice(); try { - methods.forEach((m) => m.apply(this, invocationMessage.arguments)); + methodsCopy.forEach((m) => m.apply(this, invocationMessage.arguments)); } catch (e) { this._logger.log(LogLevel.Error, `A callback for the method ${invocationMessage.target.toLowerCase()} threw error '${e}'.`); } diff --git a/src/SignalR/clients/ts/signalr/tests/HubConnection.test.ts b/src/SignalR/clients/ts/signalr/tests/HubConnection.test.ts index 1e03dbb511a..cc0f2e074cf 100644 --- a/src/SignalR/clients/ts/signalr/tests/HubConnection.test.ts +++ b/src/SignalR/clients/ts/signalr/tests/HubConnection.test.ts @@ -918,6 +918,52 @@ describe("HubConnection", () => { }); }); + it("unsubscribing dynamically doesn't affect the current invocation loop", async () => { + await VerifyLogger.run(async (logger) => { + const eventToTrack = "eventName"; + + const connection = new TestConnection(); + const hubConnection = createHubConnection(connection, logger); + try { + await hubConnection.start(); + + let numInvocations1 = 0; + let numInvocations2 = 0; + const callback1 = () => { + hubConnection.off(eventToTrack, callback1); + numInvocations1++; + } + const callback2 = () => numInvocations2++; + + hubConnection.on(eventToTrack, callback1); + hubConnection.on(eventToTrack, callback2); + + connection.receive({ + arguments: [], + nonblocking: true, + target: eventToTrack, + type: MessageType.Invocation, + }); + + expect(numInvocations1).toBe(1); + expect(numInvocations2).toBe(1); + + connection.receive({ + arguments: [], + nonblocking: true, + target: eventToTrack, + type: MessageType.Invocation, + }); + + expect(numInvocations1).toBe(1); + expect(numInvocations2).toBe(2); + } + finally { + await hubConnection.stop(); + } + }); + }); + it("unsubscribing from non-existing callbacks no-ops", async () => { await VerifyLogger.run(async (logger) => { const connection = new TestConnection(); -- GitLab