From fa93369bebb44bdb908b84b4ca3d501a2ef12c12 Mon Sep 17 00:00:00 2001 From: Brennan Date: Tue, 1 Oct 2019 15:41:06 -0700 Subject: [PATCH] Fix null reference exception for Streaming null object (#14004) (#14515) --- .../Core/src/Internal/DefaultHubDispatcher.cs | 3 +- .../HubConnectionHandlerTestUtils/Hubs.cs | 30 ++++++++++ .../SignalR/test/HubConnectionHandlerTests.cs | 58 +++++++++++++++++++ 3 files changed, 90 insertions(+), 1 deletion(-) diff --git a/src/SignalR/server/Core/src/Internal/DefaultHubDispatcher.cs b/src/SignalR/server/Core/src/Internal/DefaultHubDispatcher.cs index b0a841e1b7..0b7bd620ec 100644 --- a/src/SignalR/server/Core/src/Internal/DefaultHubDispatcher.cs +++ b/src/SignalR/server/Core/src/Internal/DefaultHubDispatcher.cs @@ -265,7 +265,8 @@ namespace Microsoft.AspNetCore.SignalR.Internal for (var parameterPointer = 0; parameterPointer < arguments.Length; parameterPointer++) { if (hubMethodInvocationMessage.Arguments.Length > hubInvocationArgumentPointer && - descriptor.OriginalParameterTypes[parameterPointer].IsAssignableFrom(hubMethodInvocationMessage.Arguments[hubInvocationArgumentPointer].GetType())) + (hubMethodInvocationMessage.Arguments[hubInvocationArgumentPointer] == null || + descriptor.OriginalParameterTypes[parameterPointer].IsAssignableFrom(hubMethodInvocationMessage.Arguments[hubInvocationArgumentPointer].GetType()))) { // The types match so it isn't a synthetic argument, just copy it into the arguments array arguments[parameterPointer] = hubMethodInvocationMessage.Arguments[hubInvocationArgumentPointer]; diff --git a/src/SignalR/server/SignalR/test/HubConnectionHandlerTestUtils/Hubs.cs b/src/SignalR/server/SignalR/test/HubConnectionHandlerTestUtils/Hubs.cs index 450697b318..3cae11661a 100644 --- a/src/SignalR/server/SignalR/test/HubConnectionHandlerTestUtils/Hubs.cs +++ b/src/SignalR/server/SignalR/test/HubConnectionHandlerTestUtils/Hubs.cs @@ -933,6 +933,36 @@ namespace Microsoft.AspNetCore.SignalR.Tests return channel.Reader; } + public ChannelReader CancelableStreamNullableParameter(int x, string y, CancellationToken token) + { + var channel = Channel.CreateBounded(10); + + Task.Run(async () => + { + _tcsService.StartedMethod.SetResult(x); + await token.WaitForCancellationAsync(); + channel.Writer.TryComplete(); + _tcsService.EndMethod.SetResult(y); + }); + + return channel.Reader; + } + + public ChannelReader StreamNullableParameter(int x, int? input) + { + var channel = Channel.CreateBounded(10); + + Task.Run(() => + { + _tcsService.StartedMethod.SetResult(x); + channel.Writer.TryComplete(); + _tcsService.EndMethod.SetResult(input); + return Task.CompletedTask; + }); + + return channel.Reader; + } + public ChannelReader CancelableStreamMiddleParameter(int ignore, CancellationToken token, int ignore2) { var channel = Channel.CreateBounded(10); diff --git a/src/SignalR/server/SignalR/test/HubConnectionHandlerTests.cs b/src/SignalR/server/SignalR/test/HubConnectionHandlerTests.cs index 9a45f00e68..c88f593db2 100644 --- a/src/SignalR/server/SignalR/test/HubConnectionHandlerTests.cs +++ b/src/SignalR/server/SignalR/test/HubConnectionHandlerTests.cs @@ -3591,6 +3591,64 @@ namespace Microsoft.AspNetCore.SignalR.Tests } } + [Fact] + public async Task StreamHubMethodCanAcceptNullableParameter() + { + using (StartVerifiableLog()) + { + var tcsService = new TcsService(); + var serviceProvider = HubConnectionHandlerTestUtils.CreateServiceProvider(builder => + { + builder.AddSingleton(tcsService); + }, LoggerFactory); + var connectionHandler = serviceProvider.GetService>(); + + using (var client = new TestClient()) + { + var connectionHandlerTask = await client.ConnectAsync(connectionHandler).OrTimeout(); + + var streamInvocationId = await client.SendStreamInvocationAsync(nameof(LongRunningHub.StreamNullableParameter), 5, null).OrTimeout(); + // Wait for the stream method to start + var firstArgument = await tcsService.StartedMethod.Task.OrTimeout(); + Assert.Equal(5, firstArgument); + + var secondArgument = await tcsService.EndMethod.Task.OrTimeout(); + Assert.Null(secondArgument); + } + } + } + + + [Fact] + public async Task StreamHubMethodCanAcceptNullableParameterWithCancellationToken() + { + using (StartVerifiableLog()) + { + var tcsService = new TcsService(); + var serviceProvider = HubConnectionHandlerTestUtils.CreateServiceProvider(builder => + { + builder.AddSingleton(tcsService); + }, LoggerFactory); + var connectionHandler = serviceProvider.GetService>(); + + using (var client = new TestClient()) + { + var connectionHandlerTask = await client.ConnectAsync(connectionHandler).OrTimeout(); + + var streamInvocationId = await client.SendStreamInvocationAsync(nameof(LongRunningHub.CancelableStreamNullableParameter), 5, null).OrTimeout(); + // Wait for the stream method to start + var firstArgument = await tcsService.StartedMethod.Task.OrTimeout(); + Assert.Equal(5, firstArgument); + + // Cancel the stream which should trigger the CancellationToken in the hub method + await client.SendHubMessageAsync(new CancelInvocationMessage(streamInvocationId)).OrTimeout(); + + var secondArgument = await tcsService.EndMethod.Task.OrTimeout(); + Assert.Null(secondArgument); + } + } + } + [Fact] public async Task InvokeHubMethodCannotAcceptCancellationTokenAsArgument() {