diff --git a/src/SignalR/server/Core/src/Internal/DefaultHubDispatcher.cs b/src/SignalR/server/Core/src/Internal/DefaultHubDispatcher.cs index cead347976a9ed0a9a0463a6c061c16afe223984..b0a841e1b7afb018b788968c8006c2d6ecc57605 100644 --- a/src/SignalR/server/Core/src/Internal/DefaultHubDispatcher.cs +++ b/src/SignalR/server/Core/src/Internal/DefaultHubDispatcher.cs @@ -316,15 +316,9 @@ namespace Microsoft.AspNetCore.SignalR.Internal _ = StreamResultsAsync(hubMethodInvocationMessage.InvocationId, connection, enumerable, scope, hubActivator, hub, cts, hubMethodInvocationMessage); } - else if (string.IsNullOrEmpty(hubMethodInvocationMessage.InvocationId)) - { - // Send Async, no response expected - invocation = ExecuteHubMethod(methodExecutor, hub, arguments); - } - else { - // Invoke Async, one reponse expected + // Invoke or Send async Task ExecuteInvocation() { object result; @@ -350,7 +344,12 @@ namespace Microsoft.AspNetCore.SignalR.Internal } } - await connection.WriteAsync(CompletionMessage.WithResult(hubMethodInvocationMessage.InvocationId, result)); + // No InvocationId - Send Async, no response expected + if (!string.IsNullOrEmpty(hubMethodInvocationMessage.InvocationId)) + { + // Invoke Async, one reponse expected + await connection.WriteAsync(CompletionMessage.WithResult(hubMethodInvocationMessage.InvocationId, result)); + } } invocation = ExecuteInvocation(); } diff --git a/src/SignalR/server/SignalR/test/HubConnectionHandlerTests.cs b/src/SignalR/server/SignalR/test/HubConnectionHandlerTests.cs index bc31d32c4c9ef7bb7eb3ea6ae9fd84a35726e3a5..9a45f00e687843bade5df971833370bc0d3630b9 100644 --- a/src/SignalR/server/SignalR/test/HubConnectionHandlerTests.cs +++ b/src/SignalR/server/SignalR/test/HubConnectionHandlerTests.cs @@ -3402,6 +3402,46 @@ namespace Microsoft.AspNetCore.SignalR.Tests } } + [Fact] + public async Task UploadStreamFromSendReleasesHubActivatorOnceComplete() + { + using (StartVerifiableLog()) + { + var serviceProvider = HubConnectionHandlerTestUtils.CreateServiceProvider(builder => + { + builder.AddSingleton(typeof(IHubActivator<>), typeof(CustomHubActivator<>)); + }, LoggerFactory); + var connectionHandler = serviceProvider.GetService<HubConnectionHandler<MethodHub>>(); + + using (var client = new TestClient()) + { + var connectionHandlerTask = await client.ConnectAsync(connectionHandler).OrTimeout(); + + var hubActivator = serviceProvider.GetService<IHubActivator<MethodHub>>() as CustomHubActivator<MethodHub>; + var createTask = hubActivator.CreateTask.Task; + + // null ID means we're doing a Send and not an Invoke + await client.BeginUploadStreamAsync(invocationId: null, nameof(MethodHub.StreamingConcat), streamIds: new[] { "id" }, args: Array.Empty<object>()).OrTimeout(); + await client.SendHubMessageAsync(new StreamItemMessage("id", "hello")).OrTimeout(); + await client.SendHubMessageAsync(new StreamItemMessage("id", " world")).OrTimeout(); + + await createTask.OrTimeout(); + var tcs = hubActivator.ReleaseTask; + await client.SendHubMessageAsync(CompletionMessage.Empty("id")).OrTimeout(); + + await tcs.Task.OrTimeout(); + + // OnConnectedAsync and StreamingConcat hubs have been disposed + Assert.Equal(2, hubActivator.ReleaseCount); + + // Shut down + client.Dispose(); + + await connectionHandlerTask.OrTimeout(); + } + } + } + [Fact] public async Task UploadStreamClosesStreamsOnServerWhenMethodCompletes() { @@ -3740,6 +3780,8 @@ namespace Microsoft.AspNetCore.SignalR.Tests { public int ReleaseCount; private IServiceProvider _serviceProvider; + public TaskCompletionSource<object> ReleaseTask = new TaskCompletionSource<object>(); + public TaskCompletionSource<object> CreateTask = new TaskCompletionSource<object>(); public CustomHubActivator(IServiceProvider serviceProvider) { @@ -3748,13 +3790,18 @@ namespace Microsoft.AspNetCore.SignalR.Tests public THub Create() { - return new DefaultHubActivator<THub>(_serviceProvider).Create(); + ReleaseTask = new TaskCompletionSource<object>(); + var hub = new DefaultHubActivator<THub>(_serviceProvider).Create(); + CreateTask.TrySetResult(null); + return hub; } public void Release(THub hub) { ReleaseCount++; hub.Dispose(); + ReleaseTask.TrySetResult(null); + CreateTask = new TaskCompletionSource<object>(); } }