diff --git a/Directory.Build.targets b/Directory.Build.targets
index 894b1d0cf8..53b3f6e1da 100644
--- a/Directory.Build.targets
+++ b/Directory.Build.targets
@@ -2,5 +2,6 @@
$(MicrosoftNETCoreApp20PackageVersion)
$(MicrosoftNETCoreApp21PackageVersion)
+ $(NETStandardLibrary20PackageVersion)
diff --git a/build/dependencies.props b/build/dependencies.props
index 856105228d..90ad79adc1 100644
--- a/build/dependencies.props
+++ b/build/dependencies.props
@@ -58,6 +58,7 @@
2.0.0
2.1.0-preview3-26413-05
15.6.1
+ 2.0.1
4.7.49
11.0.2
1.2.4
diff --git a/src/Microsoft.AspNetCore.SignalR.Core/HubConnectionHandler.cs b/src/Microsoft.AspNetCore.SignalR.Core/HubConnectionHandler.cs
index 9c7ff24e4f..668016c25e 100644
--- a/src/Microsoft.AspNetCore.SignalR.Core/HubConnectionHandler.cs
+++ b/src/Microsoft.AspNetCore.SignalR.Core/HubConnectionHandler.cs
@@ -164,9 +164,6 @@ namespace Microsoft.AspNetCore.SignalR
private async Task DispatchMessagesAsync(HubConnectionContext connection)
{
- // Since we dispatch multiple hub invocations in parallel, we need a way to communicate failure back to the main processing loop.
- // This is done by aborting the connection.
-
try
{
var input = connection.Input;
@@ -182,9 +179,9 @@ namespace Microsoft.AspNetCore.SignalR
{
while (protocol.TryParseMessage(ref buffer, _dispatcher, out var message))
{
- // Don't wait on the result of execution, continue processing other
- // incoming messages on this connection.
- _ = _dispatcher.DispatchMessageAsync(connection, message);
+ // Messages are dispatched sequentially and will block other messages from being processed until they complete.
+ // Streaming methods will run sequentially until they start streaming, then they will fire-and-forget allowing other messages to run.
+ await _dispatcher.DispatchMessageAsync(connection, message);
}
}
else if (result.IsCompleted)
diff --git a/src/Microsoft.AspNetCore.SignalR.Core/Internal/DefaultHubDispatcher.cs b/src/Microsoft.AspNetCore.SignalR.Core/Internal/DefaultHubDispatcher.cs
index 66046ebaa5..29bbbed579 100644
--- a/src/Microsoft.AspNetCore.SignalR.Core/Internal/DefaultHubDispatcher.cs
+++ b/src/Microsoft.AspNetCore.SignalR.Core/Internal/DefaultHubDispatcher.cs
@@ -170,7 +170,11 @@ namespace Microsoft.AspNetCore.SignalR.Internal
{
var methodExecutor = descriptor.MethodExecutor;
- using (var scope = _serviceScopeFactory.CreateScope())
+ var disposeScope = true;
+ var scope = _serviceScopeFactory.CreateScope();
+ IHubActivator hubActivator = null;
+ THub hub = null;
+ try
{
if (!await IsHubMethodAuthorized(scope.ServiceProvider, connection.User, descriptor.Policies))
{
@@ -185,8 +189,8 @@ namespace Microsoft.AspNetCore.SignalR.Internal
return;
}
- var hubActivator = scope.ServiceProvider.GetRequiredService>();
- var hub = hubActivator.Create();
+ hubActivator = scope.ServiceProvider.GetRequiredService>();
+ hub = hubActivator.Create();
try
{
@@ -205,8 +209,10 @@ namespace Microsoft.AspNetCore.SignalR.Internal
return;
}
+ disposeScope = false;
Log.StreamingResult(_logger, hubMethodInvocationMessage.InvocationId, methodExecutor);
- await StreamResultsAsync(hubMethodInvocationMessage.InvocationId, connection, enumerator, streamCts);
+ // Fire-and-forget stream invocations, otherwise they would block other hub invocations from being able to run
+ _ = StreamResultsAsync(hubMethodInvocationMessage.InvocationId, connection, enumerator, scope, hubActivator, hub, streamCts);
}
// Non-empty/null InvocationId ==> Blocking invocation that needs a response
else if (!string.IsNullOrEmpty(hubMethodInvocationMessage.InvocationId))
@@ -227,51 +233,60 @@ namespace Microsoft.AspNetCore.SignalR.Internal
await SendInvocationError(hubMethodInvocationMessage.InvocationId, connection,
ErrorMessageHelper.BuildErrorMessage($"An unexpected error occurred invoking '{hubMethodInvocationMessage.Target}' on the server.", ex, _enableDetailedErrors));
}
- finally
+ }
+ finally
+ {
+ if (disposeScope)
{
- hubActivator.Release(hub);
+ hubActivator?.Release(hub);
+ scope.Dispose();
}
}
}
- private async Task StreamResultsAsync(string invocationId, HubConnectionContext connection, IAsyncEnumerator