Fix #1989 by adding a 'binding failure' pseudo-message (#2064)

This commit is contained in:
Andrew Stanton-Nurse 2018-04-17 20:08:07 -07:00 committed by GitHub
parent 391c281194
commit b4046b5ed8
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
19 changed files with 173 additions and 178 deletions

View File

@ -166,67 +166,67 @@ namespace Microsoft.AspNetCore.SignalR.Microbenchmarks
[Benchmark] [Benchmark]
public Task Invocation() public Task Invocation()
{ {
return _dispatcher.DispatchMessageAsync(_connectionContext, new InvocationMessage("123", "Invocation", null, Array.Empty<object>())); return _dispatcher.DispatchMessageAsync(_connectionContext, new InvocationMessage("123", "Invocation", Array.Empty<object>()));
} }
[Benchmark] [Benchmark]
public Task InvocationAsync() public Task InvocationAsync()
{ {
return _dispatcher.DispatchMessageAsync(_connectionContext, new InvocationMessage("123", "InvocationAsync", null, Array.Empty<object>())); return _dispatcher.DispatchMessageAsync(_connectionContext, new InvocationMessage("123", "InvocationAsync", Array.Empty<object>()));
} }
[Benchmark] [Benchmark]
public Task InvocationReturnValue() public Task InvocationReturnValue()
{ {
return _dispatcher.DispatchMessageAsync(_connectionContext, new InvocationMessage("123", "InvocationReturnValue", null, Array.Empty<object>())); return _dispatcher.DispatchMessageAsync(_connectionContext, new InvocationMessage("123", "InvocationReturnValue", Array.Empty<object>()));
} }
[Benchmark] [Benchmark]
public Task InvocationReturnAsync() public Task InvocationReturnAsync()
{ {
return _dispatcher.DispatchMessageAsync(_connectionContext, new InvocationMessage("123", "InvocationReturnAsync", null, Array.Empty<object>())); return _dispatcher.DispatchMessageAsync(_connectionContext, new InvocationMessage("123", "InvocationReturnAsync", Array.Empty<object>()));
} }
[Benchmark] [Benchmark]
public Task InvocationValueTaskAsync() public Task InvocationValueTaskAsync()
{ {
return _dispatcher.DispatchMessageAsync(_connectionContext, new InvocationMessage("123", "InvocationValueTaskAsync", null, Array.Empty<object>())); return _dispatcher.DispatchMessageAsync(_connectionContext, new InvocationMessage("123", "InvocationValueTaskAsync", Array.Empty<object>()));
} }
[Benchmark] [Benchmark]
public Task StreamChannelReader() public Task StreamChannelReader()
{ {
return _dispatcher.DispatchMessageAsync(_connectionContext, new StreamInvocationMessage("123", "StreamChannelReader", null, Array.Empty<object>())); return _dispatcher.DispatchMessageAsync(_connectionContext, new StreamInvocationMessage("123", "StreamChannelReader", Array.Empty<object>()));
} }
[Benchmark] [Benchmark]
public Task StreamChannelReaderAsync() public Task StreamChannelReaderAsync()
{ {
return _dispatcher.DispatchMessageAsync(_connectionContext, new StreamInvocationMessage("123", "StreamChannelReaderAsync", null, Array.Empty<object>())); return _dispatcher.DispatchMessageAsync(_connectionContext, new StreamInvocationMessage("123", "StreamChannelReaderAsync", Array.Empty<object>()));
} }
[Benchmark] [Benchmark]
public Task StreamChannelReaderValueTaskAsync() public Task StreamChannelReaderValueTaskAsync()
{ {
return _dispatcher.DispatchMessageAsync(_connectionContext, new StreamInvocationMessage("123", "StreamChannelReaderValueTaskAsync", null, Array.Empty<object>())); return _dispatcher.DispatchMessageAsync(_connectionContext, new StreamInvocationMessage("123", "StreamChannelReaderValueTaskAsync", Array.Empty<object>()));
} }
[Benchmark] [Benchmark]
public Task StreamChannelReaderCount_Zero() public Task StreamChannelReaderCount_Zero()
{ {
return _dispatcher.DispatchMessageAsync(_connectionContext, new StreamInvocationMessage("123", "StreamChannelReaderCount", null, new object[] { 0 })); return _dispatcher.DispatchMessageAsync(_connectionContext, new StreamInvocationMessage("123", "StreamChannelReaderCount", new object[] { 0 }));
} }
[Benchmark] [Benchmark]
public Task StreamChannelReaderCount_One() public Task StreamChannelReaderCount_One()
{ {
return _dispatcher.DispatchMessageAsync(_connectionContext, new StreamInvocationMessage("123", "StreamChannelReaderCount", null, new object[] { 1 })); return _dispatcher.DispatchMessageAsync(_connectionContext, new StreamInvocationMessage("123", "StreamChannelReaderCount", new object[] { 1 }));
} }
[Benchmark] [Benchmark]
public Task StreamChannelReaderCount_Thousand() public Task StreamChannelReaderCount_Thousand()
{ {
return _dispatcher.DispatchMessageAsync(_connectionContext, new StreamInvocationMessage("123", "StreamChannelReaderCount", null, new object[] { 1000 })); return _dispatcher.DispatchMessageAsync(_connectionContext, new StreamInvocationMessage("123", "StreamChannelReaderCount", new object[] { 1000 }));
} }
} }
} }

View File

@ -37,16 +37,16 @@ namespace Microsoft.AspNetCore.SignalR.Microbenchmarks
switch (Input) switch (Input)
{ {
case Message.NoArguments: case Message.NoArguments:
_hubMessage = new InvocationMessage("Target", null, Array.Empty<object>()); _hubMessage = new InvocationMessage("Target", Array.Empty<object>());
break; break;
case Message.FewArguments: case Message.FewArguments:
_hubMessage = new InvocationMessage("Target", null, new object[] { 1, "Foo", 2.0f }); _hubMessage = new InvocationMessage("Target", new object[] { 1, "Foo", 2.0f });
break; break;
case Message.ManyArguments: case Message.ManyArguments:
_hubMessage = new InvocationMessage("Target", null, new object[] { 1, "string", 2.0f, true, (byte)9, new byte[] { 5, 4, 3, 2, 1 }, 'c', 123456789101112L }); _hubMessage = new InvocationMessage("Target", new object[] { 1, "string", 2.0f, true, (byte)9, new byte[] { 5, 4, 3, 2, 1 }, 'c', 123456789101112L });
break; break;
case Message.LargeArguments: case Message.LargeArguments:
_hubMessage = new InvocationMessage("Target", null, new object[] { new string('F', 10240), new byte[10240] }); _hubMessage = new InvocationMessage("Target", new object[] { new string('F', 10240), new byte[10240] });
break; break;
} }

View File

@ -1,4 +1,4 @@
using System; using System;
using System.Buffers; using System.Buffers;
using System.IO; using System.IO;
using System.Threading.Tasks; using System.Threading.Tasks;
@ -44,16 +44,16 @@ namespace Microsoft.AspNetCore.SignalR.Microbenchmarks
switch (Input) switch (Input)
{ {
case Message.NoArguments: case Message.NoArguments:
hubMessage = new InvocationMessage("Target", null, Array.Empty<object>()); hubMessage = new InvocationMessage("Target", Array.Empty<object>());
break; break;
case Message.FewArguments: case Message.FewArguments:
hubMessage = new InvocationMessage("Target", null, new object[] { 1, "Foo", 2.0f }); hubMessage = new InvocationMessage("Target", new object[] { 1, "Foo", 2.0f });
break; break;
case Message.ManyArguments: case Message.ManyArguments:
hubMessage = new InvocationMessage("Target", null, new object[] { 1, "string", 2.0f, true, (byte)9, new[] { 5, 4, 3, 2, 1 }, 'c', 123456789101112L }); hubMessage = new InvocationMessage("Target", new object[] { 1, "string", 2.0f, true, (byte)9, new[] { 5, 4, 3, 2, 1 }, 'c', 123456789101112L });
break; break;
case Message.LargeArguments: case Message.LargeArguments:
hubMessage = new InvocationMessage("Target", null, new object[] { new string('F', 10240), new string('B', 10240) }); hubMessage = new InvocationMessage("Target", new object[] { new string('F', 10240), new string('B', 10240) });
break; break;
} }

View File

@ -168,6 +168,9 @@ namespace Microsoft.AspNetCore.SignalR.Client
private static readonly Action<ILogger, long, Exception> _processingMessage = private static readonly Action<ILogger, long, Exception> _processingMessage =
LoggerMessage.Define<long>(LogLevel.Debug, new EventId(56, "ProcessingMessage"), "Processing {MessageLength} byte message from server."); LoggerMessage.Define<long>(LogLevel.Debug, new EventId(56, "ProcessingMessage"), "Processing {MessageLength} byte message from server.");
private static readonly Action<ILogger, string, string, Exception> _argumentBindingFailure =
LoggerMessage.Define<string, string>(LogLevel.Error, new EventId(57, "ArgumentBindingFailure"), "Failed to bind arguments received in invocation '{InvocationId}' of '{MethodName}'.");
public static void PreparingNonBlockingInvocation(ILogger logger, string target, int count) public static void PreparingNonBlockingInvocation(ILogger logger, string target, int count)
{ {
_preparingNonBlockingInvocation(logger, target, count, null); _preparingNonBlockingInvocation(logger, target, count, null);
@ -444,6 +447,11 @@ namespace Microsoft.AspNetCore.SignalR.Client
{ {
_unableToSendCancellation(logger, invocationId, null); _unableToSendCancellation(logger, invocationId, null);
} }
public static void ArgumentBindingFailure(ILogger logger, string invocationId, string target, Exception exception)
{
_argumentBindingFailure(logger, invocationId, target, exception);
}
} }
} }
} }

View File

@ -300,7 +300,7 @@ namespace Microsoft.AspNetCore.SignalR.Client
Log.PreparingBlockingInvocation(_logger, irq.InvocationId, methodName, irq.ResultType.FullName, args.Length); Log.PreparingBlockingInvocation(_logger, irq.InvocationId, methodName, irq.ResultType.FullName, args.Length);
// Client invocations are always blocking // Client invocations are always blocking
var invocationMessage = new InvocationMessage(irq.InvocationId, methodName, null, args); var invocationMessage = new InvocationMessage(irq.InvocationId, methodName, args);
Log.RegisteringInvocation(_logger, invocationMessage.InvocationId); Log.RegisteringInvocation(_logger, invocationMessage.InvocationId);
@ -327,7 +327,7 @@ namespace Microsoft.AspNetCore.SignalR.Client
Log.PreparingStreamingInvocation(_logger, irq.InvocationId, methodName, irq.ResultType.FullName, args.Length); Log.PreparingStreamingInvocation(_logger, irq.InvocationId, methodName, irq.ResultType.FullName, args.Length);
var invocationMessage = new StreamInvocationMessage(irq.InvocationId, methodName, null, args); var invocationMessage = new StreamInvocationMessage(irq.InvocationId, methodName, args);
// I just want an excuse to use 'irq' as a variable name... // I just want an excuse to use 'irq' as a variable name...
Log.RegisteringInvocation(_logger, invocationMessage.InvocationId); Log.RegisteringInvocation(_logger, invocationMessage.InvocationId);
@ -375,7 +375,7 @@ namespace Microsoft.AspNetCore.SignalR.Client
Log.PreparingNonBlockingInvocation(_logger, methodName, args.Length); Log.PreparingNonBlockingInvocation(_logger, methodName, args.Length);
var invocationMessage = new InvocationMessage(null, methodName, null, args); var invocationMessage = new InvocationMessage(null, methodName, args);
await SendHubMessage(invocationMessage, cancellationToken); await SendHubMessage(invocationMessage, cancellationToken);
} }
@ -390,9 +390,13 @@ namespace Microsoft.AspNetCore.SignalR.Client
InvocationRequest irq; InvocationRequest irq;
switch (message) switch (message)
{ {
case InvocationBindingFailureMessage bindingFailure:
// The server can't receive a response, so we just drop the message and log
// REVIEW: Is this the right approach?
Log.ArgumentBindingFailure(_logger, bindingFailure.InvocationId, bindingFailure.Target, bindingFailure.BindingFailure.SourceException);
break;
case InvocationMessage invocation: case InvocationMessage invocation:
Log.ReceivedInvocation(_logger, invocation.InvocationId, invocation.Target, Log.ReceivedInvocation(_logger, invocation.InvocationId, invocation.Target, invocation.Arguments);
invocation.ArgumentBindingException != null ? null : invocation.Arguments);
await DispatchInvocationAsync(invocation); await DispatchInvocationAsync(invocation);
break; break;
case CompletionMessage completion: case CompletionMessage completion:

View File

@ -3,33 +3,16 @@
using System; using System;
using System.Linq; using System.Linq;
using System.Runtime.ExceptionServices;
namespace Microsoft.AspNetCore.SignalR.Protocol namespace Microsoft.AspNetCore.SignalR.Protocol
{ {
public abstract class HubMethodInvocationMessage : HubInvocationMessage public abstract class HubMethodInvocationMessage : HubInvocationMessage
{ {
private readonly ExceptionDispatchInfo _argumentBindingException;
private readonly object[] _arguments;
public string Target { get; } public string Target { get; }
public object[] Arguments public object[] Arguments { get; }
{
get
{
if (_argumentBindingException != null)
{
_argumentBindingException.Throw();
}
return _arguments; protected HubMethodInvocationMessage(string invocationId, string target, object[] arguments)
}
}
public Exception ArgumentBindingException => _argumentBindingException?.SourceException;
protected HubMethodInvocationMessage(string invocationId, string target, ExceptionDispatchInfo argumentBindingException, object[] arguments)
: base(invocationId) : base(invocationId)
{ {
if (string.IsNullOrEmpty(target)) if (string.IsNullOrEmpty(target))
@ -37,26 +20,20 @@ namespace Microsoft.AspNetCore.SignalR.Protocol
throw new ArgumentNullException(nameof(target)); throw new ArgumentNullException(nameof(target));
} }
if ((arguments == null && argumentBindingException == null) || (arguments?.Length > 0 && argumentBindingException != null))
{
throw new ArgumentException($"'{nameof(argumentBindingException)}' and '{nameof(arguments)}' are mutually exclusive");
}
Target = target; Target = target;
_arguments = arguments; Arguments = arguments;
_argumentBindingException = argumentBindingException;
} }
} }
public class InvocationMessage : HubMethodInvocationMessage public class InvocationMessage : HubMethodInvocationMessage
{ {
public InvocationMessage(string target, ExceptionDispatchInfo argumentBindingException, object[] arguments) public InvocationMessage(string target, object[] arguments)
: this(null, target, argumentBindingException, arguments) : this(null, target, arguments)
{ {
} }
public InvocationMessage(string invocationId, string target, ExceptionDispatchInfo argumentBindingException, object[] arguments) public InvocationMessage(string invocationId, string target, object[] arguments)
: base(invocationId, target, argumentBindingException, arguments) : base(invocationId, target, arguments)
{ {
} }
@ -77,8 +54,8 @@ namespace Microsoft.AspNetCore.SignalR.Protocol
public class StreamInvocationMessage : HubMethodInvocationMessage public class StreamInvocationMessage : HubMethodInvocationMessage
{ {
public StreamInvocationMessage(string invocationId, string target, ExceptionDispatchInfo argumentBindingException, object[] arguments) public StreamInvocationMessage(string invocationId, string target, object[] arguments)
: base(invocationId, target, argumentBindingException, arguments) : base(invocationId, target, arguments)
{ {
if (string.IsNullOrEmpty(invocationId)) if (string.IsNullOrEmpty(invocationId))
{ {

View File

@ -0,0 +1,22 @@
using System.Runtime.ExceptionServices;
namespace Microsoft.AspNetCore.SignalR.Protocol
{
/// <summary>
/// Represents a failure to bind arguments for an invocation. This does not represent an actual
/// message that is sent on the wire, it is returned by <see cref="IHubProtocol.TryParseMessage"/>
/// to indicate that a binding failure occurred when parsing an invocation. The invocation ID is associated
/// so that the error can be sent back to the client, associated with the appropriate invocation ID.
/// </summary>
public class InvocationBindingFailureMessage : HubInvocationMessage
{
public ExceptionDispatchInfo BindingFailure { get; }
public string Target { get; }
public InvocationBindingFailureMessage(string invocationId, string target, ExceptionDispatchInfo bindingFailure) : base(invocationId)
{
Target = target;
BindingFailure = bindingFailure;
}
}
}

View File

@ -250,7 +250,7 @@ namespace Microsoft.AspNetCore.SignalR
private HubMessage CreateInvocationMessage(string methodName, object[] args) private HubMessage CreateInvocationMessage(string methodName, object[] args)
{ {
return new InvocationMessage(methodName, null, args); return new InvocationMessage(methodName, args);
} }
public override Task SendUserAsync(string userId, string methodName, object[] args) public override Task SendUserAsync(string userId, string methodName, object[] args)

View File

@ -77,6 +77,10 @@ namespace Microsoft.AspNetCore.SignalR.Internal
{ {
switch (hubMessage) switch (hubMessage)
{ {
case InvocationBindingFailureMessage bindingFailureMessage:
await ProcessBindingFailure(connection, bindingFailureMessage);
break;
case InvocationMessage invocationMessage: case InvocationMessage invocationMessage:
Log.ReceivedHubInvocation(_logger, invocationMessage); Log.ReceivedHubInvocation(_logger, invocationMessage);
await ProcessInvocation(connection, invocationMessage, isStreamedInvocation: false); await ProcessInvocation(connection, invocationMessage, isStreamedInvocation: false);
@ -113,6 +117,14 @@ namespace Microsoft.AspNetCore.SignalR.Internal
} }
} }
private Task ProcessBindingFailure(HubConnectionContext connection, InvocationBindingFailureMessage bindingFailureMessage)
{
Log.FailedInvokingHubMethod(_logger, bindingFailureMessage.Target, bindingFailureMessage.BindingFailure.SourceException);
var errorMessage = ErrorMessageHelper.BuildErrorMessage($"Failed to invoke '{bindingFailureMessage.Target}' due to an error on the server.",
bindingFailureMessage.BindingFailure.SourceException, _enableDetailedErrors);
return SendInvocationError(bindingFailureMessage.InvocationId, connection, errorMessage);
}
public override Type GetReturnType(string invocationId) public override Type GetReturnType(string invocationId)
{ {
return typeof(object); return typeof(object);
@ -163,7 +175,7 @@ namespace Microsoft.AspNetCore.SignalR.Internal
if (!await IsHubMethodAuthorized(scope.ServiceProvider, connection.User, descriptor.Policies)) if (!await IsHubMethodAuthorized(scope.ServiceProvider, connection.User, descriptor.Policies))
{ {
Log.HubMethodNotAuthorized(_logger, hubMethodInvocationMessage.Target); Log.HubMethodNotAuthorized(_logger, hubMethodInvocationMessage.Target);
await SendInvocationError(hubMethodInvocationMessage, connection, await SendInvocationError(hubMethodInvocationMessage.InvocationId, connection,
$"Failed to invoke '{hubMethodInvocationMessage.Target}' because user is unauthorized"); $"Failed to invoke '{hubMethodInvocationMessage.Target}' because user is unauthorized");
return; return;
} }
@ -173,15 +185,6 @@ namespace Microsoft.AspNetCore.SignalR.Internal
return; return;
} }
if (hubMethodInvocationMessage.ArgumentBindingException != null)
{
Log.FailedInvokingHubMethod(_logger, hubMethodInvocationMessage.Target, hubMethodInvocationMessage.ArgumentBindingException);
var errorMessage = ErrorMessageHelper.BuildErrorMessage($"Failed to invoke '{hubMethodInvocationMessage.Target}' due to an error on the server.",
hubMethodInvocationMessage.ArgumentBindingException, _enableDetailedErrors);
await SendInvocationError(hubMethodInvocationMessage, connection, errorMessage);
return;
}
var hubActivator = scope.ServiceProvider.GetRequiredService<IHubActivator<THub>>(); var hubActivator = scope.ServiceProvider.GetRequiredService<IHubActivator<THub>>();
var hub = hubActivator.Create(); var hub = hubActivator.Create();
@ -197,7 +200,7 @@ namespace Microsoft.AspNetCore.SignalR.Internal
{ {
Log.InvalidReturnValueFromStreamingMethod(_logger, methodExecutor.MethodInfo.Name); Log.InvalidReturnValueFromStreamingMethod(_logger, methodExecutor.MethodInfo.Name);
await SendInvocationError(hubMethodInvocationMessage, connection, await SendInvocationError(hubMethodInvocationMessage.InvocationId, connection,
$"The value returned by the streaming method '{methodExecutor.MethodInfo.Name}' is not a ChannelReader<>."); $"The value returned by the streaming method '{methodExecutor.MethodInfo.Name}' is not a ChannelReader<>.");
return; return;
} }
@ -215,13 +218,13 @@ namespace Microsoft.AspNetCore.SignalR.Internal
catch (TargetInvocationException ex) catch (TargetInvocationException ex)
{ {
Log.FailedInvokingHubMethod(_logger, hubMethodInvocationMessage.Target, ex); Log.FailedInvokingHubMethod(_logger, hubMethodInvocationMessage.Target, ex);
await SendInvocationError(hubMethodInvocationMessage, connection, await SendInvocationError(hubMethodInvocationMessage.InvocationId, connection,
ErrorMessageHelper.BuildErrorMessage($"An unexpected error occurred invoking '{hubMethodInvocationMessage.Target}' on the server.", ex.InnerException, _enableDetailedErrors)); ErrorMessageHelper.BuildErrorMessage($"An unexpected error occurred invoking '{hubMethodInvocationMessage.Target}' on the server.", ex.InnerException, _enableDetailedErrors));
} }
catch (Exception ex) catch (Exception ex)
{ {
Log.FailedInvokingHubMethod(_logger, hubMethodInvocationMessage.Target, ex); Log.FailedInvokingHubMethod(_logger, hubMethodInvocationMessage.Target, ex);
await SendInvocationError(hubMethodInvocationMessage, connection, await SendInvocationError(hubMethodInvocationMessage.InvocationId, connection,
ErrorMessageHelper.BuildErrorMessage($"An unexpected error occurred invoking '{hubMethodInvocationMessage.Target}' on the server.", ex, _enableDetailedErrors)); ErrorMessageHelper.BuildErrorMessage($"An unexpected error occurred invoking '{hubMethodInvocationMessage.Target}' on the server.", ex, _enableDetailedErrors));
} }
finally finally
@ -294,15 +297,15 @@ namespace Microsoft.AspNetCore.SignalR.Internal
return null; return null;
} }
private async Task SendInvocationError(HubMethodInvocationMessage hubMethodInvocationMessage, private async Task SendInvocationError(string invocationId,
HubConnectionContext connection, string errorMessage) HubConnectionContext connection, string errorMessage)
{ {
if (string.IsNullOrEmpty(hubMethodInvocationMessage.InvocationId)) if (string.IsNullOrEmpty(invocationId))
{ {
return; return;
} }
await connection.WriteAsync(CompletionMessage.WithError(hubMethodInvocationMessage.InvocationId, errorMessage)); await connection.WriteAsync(CompletionMessage.WithError(invocationId, errorMessage));
} }
private void InitializeHub(THub hub, HubConnectionContext connection) private void InitializeHub(THub hub, HubConnectionContext connection)

View File

@ -237,6 +237,7 @@ namespace Microsoft.AspNetCore.SignalR.Protocol
{ {
if (argumentsToken != null) if (argumentsToken != null)
{ {
// We weren't able to bind the arguments because they came before the 'target', so try to bind now that we've read everything.
try try
{ {
var paramTypes = binder.GetParameterTypes(target); var paramTypes = binder.GetParameterTypes(target);
@ -248,13 +249,16 @@ namespace Microsoft.AspNetCore.SignalR.Protocol
} }
} }
message = BindInvocationMessage(invocationId, target, argumentBindingException, arguments, hasArguments, binder); message = argumentBindingException != null
? new InvocationBindingFailureMessage(invocationId, target, argumentBindingException)
: BindInvocationMessage(invocationId, target, arguments, hasArguments, binder);
} }
break; break;
case HubProtocolConstants.StreamInvocationMessageType: case HubProtocolConstants.StreamInvocationMessageType:
{ {
if (argumentsToken != null) if (argumentsToken != null)
{ {
// We weren't able to bind the arguments because they came before the 'target', so try to bind now that we've read everything.
try try
{ {
var paramTypes = binder.GetParameterTypes(target); var paramTypes = binder.GetParameterTypes(target);
@ -266,7 +270,9 @@ namespace Microsoft.AspNetCore.SignalR.Protocol
} }
} }
message = BindStreamInvocationMessage(invocationId, target, argumentBindingException, arguments, hasArguments, binder); message = argumentBindingException != null
? new InvocationBindingFailureMessage(invocationId, target, argumentBindingException)
: BindStreamInvocationMessage(invocationId, target, arguments, hasArguments, binder);
} }
break; break;
case HubProtocolConstants.StreamItemMessageType: case HubProtocolConstants.StreamItemMessageType:
@ -539,7 +545,7 @@ namespace Microsoft.AspNetCore.SignalR.Protocol
return new StreamItemMessage(invocationId, item); return new StreamItemMessage(invocationId, item);
} }
private HubMessage BindStreamInvocationMessage(string invocationId, string target, ExceptionDispatchInfo argumentBindingException, object[] arguments, bool hasArguments, IInvocationBinder binder) private HubMessage BindStreamInvocationMessage(string invocationId, string target, object[] arguments, bool hasArguments, IInvocationBinder binder)
{ {
if (string.IsNullOrEmpty(invocationId)) if (string.IsNullOrEmpty(invocationId))
{ {
@ -556,10 +562,10 @@ namespace Microsoft.AspNetCore.SignalR.Protocol
throw new InvalidDataException($"Missing required property '{TargetPropertyName}'."); throw new InvalidDataException($"Missing required property '{TargetPropertyName}'.");
} }
return new StreamInvocationMessage(invocationId, target, argumentBindingException, arguments); return new StreamInvocationMessage(invocationId, target, arguments);
} }
private HubMessage BindInvocationMessage(string invocationId, string target, ExceptionDispatchInfo argumentBindingException, object[] arguments, bool hasArguments, IInvocationBinder binder) private HubMessage BindInvocationMessage(string invocationId, string target, object[] arguments, bool hasArguments, IInvocationBinder binder)
{ {
if (string.IsNullOrEmpty(target)) if (string.IsNullOrEmpty(target))
{ {
@ -571,7 +577,7 @@ namespace Microsoft.AspNetCore.SignalR.Protocol
throw new InvalidDataException($"Missing required property '{ArgumentsPropertyName}'."); throw new InvalidDataException($"Missing required property '{ArgumentsPropertyName}'.");
} }
return new InvocationMessage(invocationId, target, argumentBindingException, arguments); return new InvocationMessage(invocationId, target, arguments);
} }
private object[] BindArguments(JsonTextReader reader, IReadOnlyList<Type> paramTypes) private object[] BindArguments(JsonTextReader reader, IReadOnlyList<Type> paramTypes)

View File

@ -129,7 +129,7 @@ namespace Microsoft.AspNetCore.SignalR.Protocol
} }
} }
private static InvocationMessage CreateInvocationMessage(byte[] input, ref int offset, IInvocationBinder binder, IFormatterResolver resolver) private static HubMessage CreateInvocationMessage(byte[] input, ref int offset, IInvocationBinder binder, IFormatterResolver resolver)
{ {
var headers = ReadHeaders(input, ref offset); var headers = ReadHeaders(input, ref offset);
var invocationId = ReadInvocationId(input, ref offset); var invocationId = ReadInvocationId(input, ref offset);
@ -147,15 +147,15 @@ namespace Microsoft.AspNetCore.SignalR.Protocol
try try
{ {
var arguments = BindArguments(input, ref offset, parameterTypes, resolver); var arguments = BindArguments(input, ref offset, parameterTypes, resolver);
return ApplyHeaders(headers, new InvocationMessage(invocationId, target, null, arguments)); return ApplyHeaders(headers, new InvocationMessage(invocationId, target, arguments));
} }
catch (Exception ex) catch (Exception ex)
{ {
return ApplyHeaders(headers, new InvocationMessage(invocationId, target, ExceptionDispatchInfo.Capture(ex), null)); return new InvocationBindingFailureMessage(invocationId, target, ExceptionDispatchInfo.Capture(ex));
} }
} }
private static StreamInvocationMessage CreateStreamInvocationMessage(byte[] input, ref int offset, IInvocationBinder binder, IFormatterResolver resolver) private static HubMessage CreateStreamInvocationMessage(byte[] input, ref int offset, IInvocationBinder binder, IFormatterResolver resolver)
{ {
var headers = ReadHeaders(input, ref offset); var headers = ReadHeaders(input, ref offset);
var invocationId = ReadInvocationId(input, ref offset); var invocationId = ReadInvocationId(input, ref offset);
@ -165,11 +165,11 @@ namespace Microsoft.AspNetCore.SignalR.Protocol
try try
{ {
var arguments = BindArguments(input, ref offset, parameterTypes, resolver); var arguments = BindArguments(input, ref offset, parameterTypes, resolver);
return ApplyHeaders(headers, new StreamInvocationMessage(invocationId, target, null, arguments)); return ApplyHeaders(headers, new StreamInvocationMessage(invocationId, target, arguments));
} }
catch (Exception ex) catch (Exception ex)
{ {
return ApplyHeaders(headers, new StreamInvocationMessage(invocationId, target, ExceptionDispatchInfo.Capture(ex), null)); return new InvocationBindingFailureMessage(invocationId, target, ExceptionDispatchInfo.Capture(ex));
} }
} }

View File

@ -62,7 +62,7 @@ namespace Microsoft.AspNetCore.SignalR.Redis.Internal
} }
WriteSerializedHubMessage(writer, WriteSerializedHubMessage(writer,
new SerializedHubMessage(new InvocationMessage(methodName, null, args))); new SerializedHubMessage(new InvocationMessage(methodName, args)));
return writer.ToArray(); return writer.ToArray();
} }
finally finally

View File

@ -130,7 +130,7 @@ namespace Microsoft.AspNetCore.SignalR.Redis
var connection = _connections[connectionId]; var connection = _connections[connectionId];
if (connection != null) if (connection != null)
{ {
return connection.WriteAsync(new InvocationMessage(methodName, null, args)).AsTask(); return connection.WriteAsync(new InvocationMessage(methodName, args)).AsTask();
} }
var message = _protocol.WriteInvocation(methodName, args); var message = _protocol.WriteInvocation(methodName, args);

View File

@ -32,17 +32,17 @@ namespace Microsoft.AspNetCore.SignalR.Common.Tests.Internal.Protocol
public static IDictionary<string, JsonProtocolTestData> ProtocolTestData => new[] public static IDictionary<string, JsonProtocolTestData> ProtocolTestData => new[]
{ {
new JsonProtocolTestData("InvocationMessage_HasInvocationId", new InvocationMessage("123", "Target", null, new object[] { 1, "Foo", 2.0f }), true, NullValueHandling.Ignore, "{\"type\":1,\"invocationId\":\"123\",\"target\":\"Target\",\"arguments\":[1,\"Foo\",2.0]}"), new JsonProtocolTestData("InvocationMessage_HasInvocationId", new InvocationMessage("123", "Target", new object[] { 1, "Foo", 2.0f }), true, NullValueHandling.Ignore, "{\"type\":1,\"invocationId\":\"123\",\"target\":\"Target\",\"arguments\":[1,\"Foo\",2.0]}"),
new JsonProtocolTestData("InvocationMessage_HasFloatArgument", new InvocationMessage(null, "Target", null, new object[] { 1, "Foo", 2.0f }), true, NullValueHandling.Ignore, "{\"type\":1,\"target\":\"Target\",\"arguments\":[1,\"Foo\",2.0]}"), new JsonProtocolTestData("InvocationMessage_HasFloatArgument", new InvocationMessage(null, "Target", new object[] { 1, "Foo", 2.0f }), true, NullValueHandling.Ignore, "{\"type\":1,\"target\":\"Target\",\"arguments\":[1,\"Foo\",2.0]}"),
new JsonProtocolTestData("InvocationMessage_HasBoolArgument", new InvocationMessage(null, "Target", null, new object[] { true }), true, NullValueHandling.Ignore, "{\"type\":1,\"target\":\"Target\",\"arguments\":[true]}"), new JsonProtocolTestData("InvocationMessage_HasBoolArgument", new InvocationMessage(null, "Target", new object[] { true }), true, NullValueHandling.Ignore, "{\"type\":1,\"target\":\"Target\",\"arguments\":[true]}"),
new JsonProtocolTestData("InvocationMessage_HasNullArgument", new InvocationMessage(null, "Target", null, new object[] { null }), true, NullValueHandling.Ignore, "{\"type\":1,\"target\":\"Target\",\"arguments\":[null]}"), new JsonProtocolTestData("InvocationMessage_HasNullArgument", new InvocationMessage(null, "Target", new object[] { null }), true, NullValueHandling.Ignore, "{\"type\":1,\"target\":\"Target\",\"arguments\":[null]}"),
new JsonProtocolTestData("InvocationMessage_HasCustomArgumentWithNoCamelCase", new InvocationMessage(null, "Target", null, new object[] { new CustomObject() }), false, NullValueHandling.Ignore, "{\"type\":1,\"target\":\"Target\",\"arguments\":[{\"StringProp\":\"SignalR!\",\"DoubleProp\":6.2831853071,\"IntProp\":42,\"DateTimeProp\":\"2017-04-11T00:00:00Z\",\"ByteArrProp\":\"AQID\"}]}"), new JsonProtocolTestData("InvocationMessage_HasCustomArgumentWithNoCamelCase", new InvocationMessage(null, "Target", new object[] { new CustomObject() }), false, NullValueHandling.Ignore, "{\"type\":1,\"target\":\"Target\",\"arguments\":[{\"StringProp\":\"SignalR!\",\"DoubleProp\":6.2831853071,\"IntProp\":42,\"DateTimeProp\":\"2017-04-11T00:00:00Z\",\"ByteArrProp\":\"AQID\"}]}"),
new JsonProtocolTestData("InvocationMessage_HasCustomArgumentWithNullValueIgnore", new InvocationMessage(null, "Target", null, new object[] { new CustomObject() }), true, NullValueHandling.Ignore, "{\"type\":1,\"target\":\"Target\",\"arguments\":[{\"stringProp\":\"SignalR!\",\"doubleProp\":6.2831853071,\"intProp\":42,\"dateTimeProp\":\"2017-04-11T00:00:00Z\",\"byteArrProp\":\"AQID\"}]}"), new JsonProtocolTestData("InvocationMessage_HasCustomArgumentWithNullValueIgnore", new InvocationMessage(null, "Target", new object[] { new CustomObject() }), true, NullValueHandling.Ignore, "{\"type\":1,\"target\":\"Target\",\"arguments\":[{\"stringProp\":\"SignalR!\",\"doubleProp\":6.2831853071,\"intProp\":42,\"dateTimeProp\":\"2017-04-11T00:00:00Z\",\"byteArrProp\":\"AQID\"}]}"),
new JsonProtocolTestData("InvocationMessage_HasCustomArgumentWithNullValueIgnoreAndNoCamelCase", new InvocationMessage(null, "Target", null, new object[] { new CustomObject() }), false, NullValueHandling.Include, "{\"type\":1,\"target\":\"Target\",\"arguments\":[{\"StringProp\":\"SignalR!\",\"DoubleProp\":6.2831853071,\"IntProp\":42,\"DateTimeProp\":\"2017-04-11T00:00:00Z\",\"NullProp\":null,\"ByteArrProp\":\"AQID\"}]}"), new JsonProtocolTestData("InvocationMessage_HasCustomArgumentWithNullValueIgnoreAndNoCamelCase", new InvocationMessage(null, "Target", new object[] { new CustomObject() }), false, NullValueHandling.Include, "{\"type\":1,\"target\":\"Target\",\"arguments\":[{\"StringProp\":\"SignalR!\",\"DoubleProp\":6.2831853071,\"IntProp\":42,\"DateTimeProp\":\"2017-04-11T00:00:00Z\",\"NullProp\":null,\"ByteArrProp\":\"AQID\"}]}"),
new JsonProtocolTestData("InvocationMessage_HasCustomArgumentWithNullValueInclude", new InvocationMessage(null, "Target", null, new object[] { new CustomObject() }), true, NullValueHandling.Include, "{\"type\":1,\"target\":\"Target\",\"arguments\":[{\"stringProp\":\"SignalR!\",\"doubleProp\":6.2831853071,\"intProp\":42,\"dateTimeProp\":\"2017-04-11T00:00:00Z\",\"nullProp\":null,\"byteArrProp\":\"AQID\"}]}"), new JsonProtocolTestData("InvocationMessage_HasCustomArgumentWithNullValueInclude", new InvocationMessage(null, "Target", new object[] { new CustomObject() }), true, NullValueHandling.Include, "{\"type\":1,\"target\":\"Target\",\"arguments\":[{\"stringProp\":\"SignalR!\",\"doubleProp\":6.2831853071,\"intProp\":42,\"dateTimeProp\":\"2017-04-11T00:00:00Z\",\"nullProp\":null,\"byteArrProp\":\"AQID\"}]}"),
new JsonProtocolTestData("InvocationMessage_HasHeaders", AddHeaders(TestHeaders, new InvocationMessage("123", "Target", null, new object[] { 1, "Foo", 2.0f })), true, NullValueHandling.Ignore, "{\"type\":1," + SerializedHeaders + ",\"invocationId\":\"123\",\"target\":\"Target\",\"arguments\":[1,\"Foo\",2.0]}"), new JsonProtocolTestData("InvocationMessage_HasHeaders", AddHeaders(TestHeaders, new InvocationMessage("123", "Target", new object[] { 1, "Foo", 2.0f })), true, NullValueHandling.Ignore, "{\"type\":1," + SerializedHeaders + ",\"invocationId\":\"123\",\"target\":\"Target\",\"arguments\":[1,\"Foo\",2.0]}"),
new JsonProtocolTestData("InvocationMessage_StringIsoDateArgument", new InvocationMessage("Method", null, new object[] { "2016-05-10T13:51:20+12:34" }), true, NullValueHandling.Ignore, "{\"type\":1,\"target\":\"Method\",\"arguments\":[\"2016-05-10T13:51:20+12:34\"]}"), new JsonProtocolTestData("InvocationMessage_StringIsoDateArgument", new InvocationMessage("Method", new object[] { "2016-05-10T13:51:20+12:34" }), true, NullValueHandling.Ignore, "{\"type\":1,\"target\":\"Method\",\"arguments\":[\"2016-05-10T13:51:20+12:34\"]}"),
new JsonProtocolTestData("InvocationMessage_DateTimeOffsetArgument", new InvocationMessage("Method", null, new object[] { DateTimeOffset.Parse("2016-05-10T13:51:20+12:34") }), true, NullValueHandling.Ignore, "{\"type\":1,\"target\":\"Method\",\"arguments\":[\"2016-05-10T13:51:20+12:34\"]}"), new JsonProtocolTestData("InvocationMessage_DateTimeOffsetArgument", new InvocationMessage("Method", new object[] { DateTimeOffset.Parse("2016-05-10T13:51:20+12:34") }), true, NullValueHandling.Ignore, "{\"type\":1,\"target\":\"Method\",\"arguments\":[\"2016-05-10T13:51:20+12:34\"]}"),
new JsonProtocolTestData("StreamItemMessage_HasIntegerItem", new StreamItemMessage("123", 1), true, NullValueHandling.Ignore, "{\"type\":2,\"invocationId\":\"123\",\"item\":1}"), new JsonProtocolTestData("StreamItemMessage_HasIntegerItem", new StreamItemMessage("123", 1), true, NullValueHandling.Ignore, "{\"type\":2,\"invocationId\":\"123\",\"item\":1}"),
new JsonProtocolTestData("StreamItemMessage_HasStringItem", new StreamItemMessage("123", "Foo"), true, NullValueHandling.Ignore, "{\"type\":2,\"invocationId\":\"123\",\"item\":\"Foo\"}"), new JsonProtocolTestData("StreamItemMessage_HasStringItem", new StreamItemMessage("123", "Foo"), true, NullValueHandling.Ignore, "{\"type\":2,\"invocationId\":\"123\",\"item\":\"Foo\"}"),
@ -70,15 +70,15 @@ namespace Microsoft.AspNetCore.SignalR.Common.Tests.Internal.Protocol
new JsonProtocolTestData("CompletionMessage_HasErrorAndCamelCase", CompletionMessage.Empty("123"), true, NullValueHandling.Ignore, "{\"type\":3,\"invocationId\":\"123\"}"), new JsonProtocolTestData("CompletionMessage_HasErrorAndCamelCase", CompletionMessage.Empty("123"), true, NullValueHandling.Ignore, "{\"type\":3,\"invocationId\":\"123\"}"),
new JsonProtocolTestData("CompletionMessage_HasErrorAndHeadersAndCamelCase", AddHeaders(TestHeaders, CompletionMessage.Empty("123")), true, NullValueHandling.Ignore, "{\"type\":3," + SerializedHeaders + ",\"invocationId\":\"123\"}"), new JsonProtocolTestData("CompletionMessage_HasErrorAndHeadersAndCamelCase", AddHeaders(TestHeaders, CompletionMessage.Empty("123")), true, NullValueHandling.Ignore, "{\"type\":3," + SerializedHeaders + ",\"invocationId\":\"123\"}"),
new JsonProtocolTestData("StreamInvocationMessage_HasInvocationId", new StreamInvocationMessage("123", "Target", null, new object[] { 1, "Foo", 2.0f }), true, NullValueHandling.Ignore, "{\"type\":4,\"invocationId\":\"123\",\"target\":\"Target\",\"arguments\":[1,\"Foo\",2.0]}"), new JsonProtocolTestData("StreamInvocationMessage_HasInvocationId", new StreamInvocationMessage("123", "Target", new object[] { 1, "Foo", 2.0f }), true, NullValueHandling.Ignore, "{\"type\":4,\"invocationId\":\"123\",\"target\":\"Target\",\"arguments\":[1,\"Foo\",2.0]}"),
new JsonProtocolTestData("StreamInvocationMessage_HasFloatArgument", new StreamInvocationMessage("123", "Target", null, new object[] { 1, "Foo", 2.0f }), true, NullValueHandling.Ignore, "{\"type\":4,\"invocationId\":\"123\",\"target\":\"Target\",\"arguments\":[1,\"Foo\",2.0]}"), new JsonProtocolTestData("StreamInvocationMessage_HasFloatArgument", new StreamInvocationMessage("123", "Target", new object[] { 1, "Foo", 2.0f }), true, NullValueHandling.Ignore, "{\"type\":4,\"invocationId\":\"123\",\"target\":\"Target\",\"arguments\":[1,\"Foo\",2.0]}"),
new JsonProtocolTestData("StreamInvocationMessage_HasBoolArgument", new StreamInvocationMessage("123", "Target", null, new object[] { true }), true, NullValueHandling.Ignore, "{\"type\":4,\"invocationId\":\"123\",\"target\":\"Target\",\"arguments\":[true]}"), new JsonProtocolTestData("StreamInvocationMessage_HasBoolArgument", new StreamInvocationMessage("123", "Target", new object[] { true }), true, NullValueHandling.Ignore, "{\"type\":4,\"invocationId\":\"123\",\"target\":\"Target\",\"arguments\":[true]}"),
new JsonProtocolTestData("StreamInvocationMessage_HasNullArgument", new StreamInvocationMessage("123", "Target", null, new object[] { null }), true, NullValueHandling.Ignore, "{\"type\":4,\"invocationId\":\"123\",\"target\":\"Target\",\"arguments\":[null]}"), new JsonProtocolTestData("StreamInvocationMessage_HasNullArgument", new StreamInvocationMessage("123", "Target", new object[] { null }), true, NullValueHandling.Ignore, "{\"type\":4,\"invocationId\":\"123\",\"target\":\"Target\",\"arguments\":[null]}"),
new JsonProtocolTestData("StreamInvocationMessage_HasCustomArgumentWithNoCamelCase", new StreamInvocationMessage("123", "Target", null, new object[] { new CustomObject() }), false, NullValueHandling.Ignore, "{\"type\":4,\"invocationId\":\"123\",\"target\":\"Target\",\"arguments\":[{\"StringProp\":\"SignalR!\",\"DoubleProp\":6.2831853071,\"IntProp\":42,\"DateTimeProp\":\"2017-04-11T00:00:00Z\",\"ByteArrProp\":\"AQID\"}]}"), new JsonProtocolTestData("StreamInvocationMessage_HasCustomArgumentWithNoCamelCase", new StreamInvocationMessage("123", "Target", new object[] { new CustomObject() }), false, NullValueHandling.Ignore, "{\"type\":4,\"invocationId\":\"123\",\"target\":\"Target\",\"arguments\":[{\"StringProp\":\"SignalR!\",\"DoubleProp\":6.2831853071,\"IntProp\":42,\"DateTimeProp\":\"2017-04-11T00:00:00Z\",\"ByteArrProp\":\"AQID\"}]}"),
new JsonProtocolTestData("StreamInvocationMessage_HasCustomArgumentWithNullValueIgnore", new StreamInvocationMessage("123", "Target", null, new object[] { new CustomObject() }), true, NullValueHandling.Ignore, "{\"type\":4,\"invocationId\":\"123\",\"target\":\"Target\",\"arguments\":[{\"stringProp\":\"SignalR!\",\"doubleProp\":6.2831853071,\"intProp\":42,\"dateTimeProp\":\"2017-04-11T00:00:00Z\",\"byteArrProp\":\"AQID\"}]}"), new JsonProtocolTestData("StreamInvocationMessage_HasCustomArgumentWithNullValueIgnore", new StreamInvocationMessage("123", "Target", new object[] { new CustomObject() }), true, NullValueHandling.Ignore, "{\"type\":4,\"invocationId\":\"123\",\"target\":\"Target\",\"arguments\":[{\"stringProp\":\"SignalR!\",\"doubleProp\":6.2831853071,\"intProp\":42,\"dateTimeProp\":\"2017-04-11T00:00:00Z\",\"byteArrProp\":\"AQID\"}]}"),
new JsonProtocolTestData("StreamInvocationMessage_HasCustomArgumentWithNullValueIgnoreAndNoCamelCase", new StreamInvocationMessage("123", "Target", null, new object[] { new CustomObject() }), false, NullValueHandling.Include, "{\"type\":4,\"invocationId\":\"123\",\"target\":\"Target\",\"arguments\":[{\"StringProp\":\"SignalR!\",\"DoubleProp\":6.2831853071,\"IntProp\":42,\"DateTimeProp\":\"2017-04-11T00:00:00Z\",\"NullProp\":null,\"ByteArrProp\":\"AQID\"}]}"), new JsonProtocolTestData("StreamInvocationMessage_HasCustomArgumentWithNullValueIgnoreAndNoCamelCase", new StreamInvocationMessage("123", "Target", new object[] { new CustomObject() }), false, NullValueHandling.Include, "{\"type\":4,\"invocationId\":\"123\",\"target\":\"Target\",\"arguments\":[{\"StringProp\":\"SignalR!\",\"DoubleProp\":6.2831853071,\"IntProp\":42,\"DateTimeProp\":\"2017-04-11T00:00:00Z\",\"NullProp\":null,\"ByteArrProp\":\"AQID\"}]}"),
new JsonProtocolTestData("StreamInvocationMessage_HasCustomArgumentWithNullValueInclude", new StreamInvocationMessage("123", "Target", null, new object[] { new CustomObject() }), true, NullValueHandling.Include, "{\"type\":4,\"invocationId\":\"123\",\"target\":\"Target\",\"arguments\":[{\"stringProp\":\"SignalR!\",\"doubleProp\":6.2831853071,\"intProp\":42,\"dateTimeProp\":\"2017-04-11T00:00:00Z\",\"nullProp\":null,\"byteArrProp\":\"AQID\"}]}"), new JsonProtocolTestData("StreamInvocationMessage_HasCustomArgumentWithNullValueInclude", new StreamInvocationMessage("123", "Target", new object[] { new CustomObject() }), true, NullValueHandling.Include, "{\"type\":4,\"invocationId\":\"123\",\"target\":\"Target\",\"arguments\":[{\"stringProp\":\"SignalR!\",\"doubleProp\":6.2831853071,\"intProp\":42,\"dateTimeProp\":\"2017-04-11T00:00:00Z\",\"nullProp\":null,\"byteArrProp\":\"AQID\"}]}"),
new JsonProtocolTestData("StreamInvocationMessage_HasHeaders", AddHeaders(TestHeaders, new StreamInvocationMessage("123", "Target", null, new object[] { new CustomObject() })), true, NullValueHandling.Include, "{\"type\":4," + SerializedHeaders + ",\"invocationId\":\"123\",\"target\":\"Target\",\"arguments\":[{\"stringProp\":\"SignalR!\",\"doubleProp\":6.2831853071,\"intProp\":42,\"dateTimeProp\":\"2017-04-11T00:00:00Z\",\"nullProp\":null,\"byteArrProp\":\"AQID\"}]}"), new JsonProtocolTestData("StreamInvocationMessage_HasHeaders", AddHeaders(TestHeaders, new StreamInvocationMessage("123", "Target", new object[] { new CustomObject() })), true, NullValueHandling.Include, "{\"type\":4," + SerializedHeaders + ",\"invocationId\":\"123\",\"target\":\"Target\",\"arguments\":[{\"stringProp\":\"SignalR!\",\"doubleProp\":6.2831853071,\"intProp\":42,\"dateTimeProp\":\"2017-04-11T00:00:00Z\",\"nullProp\":null,\"byteArrProp\":\"AQID\"}]}"),
new JsonProtocolTestData("CancelInvocationMessage_HasInvocationId", new CancelInvocationMessage("123"), true, NullValueHandling.Ignore, "{\"type\":5,\"invocationId\":\"123\"}"), new JsonProtocolTestData("CancelInvocationMessage_HasInvocationId", new CancelInvocationMessage("123"), true, NullValueHandling.Ignore, "{\"type\":5,\"invocationId\":\"123\"}"),
new JsonProtocolTestData("CancelInvocationMessage_HasHeaders", AddHeaders(TestHeaders, new CancelInvocationMessage("123")), true, NullValueHandling.Ignore, "{\"type\":5," + SerializedHeaders + ",\"invocationId\":\"123\"}"), new JsonProtocolTestData("CancelInvocationMessage_HasHeaders", AddHeaders(TestHeaders, new CancelInvocationMessage("123")), true, NullValueHandling.Ignore, "{\"type\":5," + SerializedHeaders + ",\"invocationId\":\"123\"}"),
@ -95,10 +95,10 @@ namespace Microsoft.AspNetCore.SignalR.Common.Tests.Internal.Protocol
public static IDictionary<string, JsonProtocolTestData> OutOfOrderJsonTestData => new[] public static IDictionary<string, JsonProtocolTestData> OutOfOrderJsonTestData => new[]
{ {
new JsonProtocolTestData("InvocationMessage_StringIsoDateArgumentFirst", new InvocationMessage("Method", null, new object[] { "2016-05-10T13:51:20+12:34" }), false, NullValueHandling.Ignore, "{ \"arguments\": [\"2016-05-10T13:51:20+12:34\"], \"type\":1, \"target\": \"Method\" }"), new JsonProtocolTestData("InvocationMessage_StringIsoDateArgumentFirst", new InvocationMessage("Method", new object[] { "2016-05-10T13:51:20+12:34" }), false, NullValueHandling.Ignore, "{ \"arguments\": [\"2016-05-10T13:51:20+12:34\"], \"type\":1, \"target\": \"Method\" }"),
new JsonProtocolTestData("InvocationMessage_DateTimeOffsetArgumentFirst", new InvocationMessage("Method", null, new object[] { DateTimeOffset.Parse("2016-05-10T13:51:20+12:34") }), false, NullValueHandling.Ignore, "{ \"arguments\": [\"2016-05-10T13:51:20+12:34\"], \"type\":1, \"target\": \"Method\" }"), new JsonProtocolTestData("InvocationMessage_DateTimeOffsetArgumentFirst", new InvocationMessage("Method", new object[] { DateTimeOffset.Parse("2016-05-10T13:51:20+12:34") }), false, NullValueHandling.Ignore, "{ \"arguments\": [\"2016-05-10T13:51:20+12:34\"], \"type\":1, \"target\": \"Method\" }"),
new JsonProtocolTestData("InvocationMessage_IntegerArrayArgumentFirst", new InvocationMessage("Method", null, new object[] { 1, 2 }), false, NullValueHandling.Ignore, "{ \"arguments\": [1,2], \"type\":1, \"target\": \"Method\" }"), new JsonProtocolTestData("InvocationMessage_IntegerArrayArgumentFirst", new InvocationMessage("Method", new object[] { 1, 2 }), false, NullValueHandling.Ignore, "{ \"arguments\": [1,2], \"type\":1, \"target\": \"Method\" }"),
new JsonProtocolTestData("StreamInvocationMessage_IntegerArrayArgumentFirst", new StreamInvocationMessage("3", "Method", null, new object[] { 1, 2 }), false, NullValueHandling.Ignore, "{ \"type\":4, \"arguments\": [1,2], \"target\": \"Method\", \"invocationId\": \"3\" }"), new JsonProtocolTestData("StreamInvocationMessage_IntegerArrayArgumentFirst", new StreamInvocationMessage("3", "Method", new object[] { 1, 2 }), false, NullValueHandling.Ignore, "{ \"type\":4, \"arguments\": [1,2], \"target\": \"Method\", \"invocationId\": \"3\" }"),
new JsonProtocolTestData("CompletionMessage_ResultFirst", new CompletionMessage("15", null, 10, hasResult: true), false, NullValueHandling.Ignore, "{ \"type\":3, \"result\": 10, \"invocationId\": \"15\" }"), new JsonProtocolTestData("CompletionMessage_ResultFirst", new CompletionMessage("15", null, 10, hasResult: true), false, NullValueHandling.Ignore, "{ \"type\":3, \"result\": 10, \"invocationId\": \"15\" }"),
new JsonProtocolTestData("StreamItemMessage_ItemFirst", new StreamItemMessage("1a", "foo"), false, NullValueHandling.Ignore, "{ \"item\": \"foo\", \"invocationId\": \"1a\", \"type\":2 }") new JsonProtocolTestData("StreamItemMessage_ItemFirst", new StreamItemMessage("1a", "foo"), false, NullValueHandling.Ignore, "{ \"item\": \"foo\", \"invocationId\": \"1a\", \"type\":2 }")
}.ToDictionary(t => t.Name); }.ToDictionary(t => t.Name);
@ -256,8 +256,8 @@ namespace Microsoft.AspNetCore.SignalR.Common.Tests.Internal.Protocol
var protocol = new JsonHubProtocol(); var protocol = new JsonHubProtocol();
var data = new ReadOnlySequence<byte>(Encoding.UTF8.GetBytes(input)); var data = new ReadOnlySequence<byte>(Encoding.UTF8.GetBytes(input));
protocol.TryParseMessage(ref data, binder, out var message); protocol.TryParseMessage(ref data, binder, out var message);
var ex = Assert.Throws<InvalidDataException>(() => ((HubMethodInvocationMessage)message).Arguments); var bindingFailure = Assert.IsType<InvocationBindingFailureMessage>(message);
Assert.Equal(expectedMessage, ex.Message); Assert.Equal(expectedMessage, bindingFailure.BindingFailure.SourceException.Message);
} }
private static string Frame(string input) private static string Frame(string input)

View File

@ -57,39 +57,39 @@ namespace Microsoft.AspNetCore.SignalR.Common.Tests.Internal.Protocol
// Invocation messages // Invocation messages
new ProtocolTestData( new ProtocolTestData(
name: "InvocationWithNoHeadersAndNoArgs", name: "InvocationWithNoHeadersAndNoArgs",
message: new InvocationMessage("xyz", "method", null, Array.Empty<object>()), message: new InvocationMessage("xyz", "method", Array.Empty<object>()),
binary: "lQGAo3h5eqZtZXRob2SQ"), binary: "lQGAo3h5eqZtZXRob2SQ"),
new ProtocolTestData( new ProtocolTestData(
name: "InvocationWithNoHeadersNoIdAndNoArgs", name: "InvocationWithNoHeadersNoIdAndNoArgs",
message: new InvocationMessage("method", null, Array.Empty<object>()), message: new InvocationMessage("method", Array.Empty<object>()),
binary: "lQGAwKZtZXRob2SQ"), binary: "lQGAwKZtZXRob2SQ"),
new ProtocolTestData( new ProtocolTestData(
name: "InvocationWithNoHeadersNoIdAndSingleNullArg", name: "InvocationWithNoHeadersNoIdAndSingleNullArg",
message: new InvocationMessage("method", null, new object[] { null }), message: new InvocationMessage("method", new object[] { null }),
binary: "lQGAwKZtZXRob2SRwA=="), binary: "lQGAwKZtZXRob2SRwA=="),
new ProtocolTestData( new ProtocolTestData(
name: "InvocationWithNoHeadersNoIdAndSingleIntArg", name: "InvocationWithNoHeadersNoIdAndSingleIntArg",
message: new InvocationMessage("method", null, new object[] { 42 }), message: new InvocationMessage("method", new object[] { 42 }),
binary: "lQGAwKZtZXRob2SRKg=="), binary: "lQGAwKZtZXRob2SRKg=="),
new ProtocolTestData( new ProtocolTestData(
name: "InvocationWithNoHeadersNoIdIntAndStringArgs", name: "InvocationWithNoHeadersNoIdIntAndStringArgs",
message: new InvocationMessage("method", null, new object[] { 42, "string" }), message: new InvocationMessage("method", new object[] { 42, "string" }),
binary: "lQGAwKZtZXRob2SSKqZzdHJpbmc="), binary: "lQGAwKZtZXRob2SSKqZzdHJpbmc="),
new ProtocolTestData( new ProtocolTestData(
name: "InvocationWithNoHeadersNoIdIntAndEnumArgs", name: "InvocationWithNoHeadersNoIdIntAndEnumArgs",
message: new InvocationMessage("method", null, new object[] { 42, TestEnum.One }), message: new InvocationMessage("method", new object[] { 42, TestEnum.One }),
binary: "lQGAwKZtZXRob2SSKqNPbmU="), binary: "lQGAwKZtZXRob2SSKqNPbmU="),
new ProtocolTestData( new ProtocolTestData(
name: "InvocationWithNoHeadersNoIdAndCustomObjectArg", name: "InvocationWithNoHeadersNoIdAndCustomObjectArg",
message: new InvocationMessage("method", null, new object[] { 42, "string", new CustomObject() }), message: new InvocationMessage("method", new object[] { 42, "string", new CustomObject() }),
binary: "lQGAwKZtZXRob2STKqZzdHJpbmeGqlN0cmluZ1Byb3CoU2lnbmFsUiGqRG91YmxlUHJvcMtAGSH7VELPEqdJbnRQcm9wKqxEYXRlVGltZVByb3DW/1jsHICoTnVsbFByb3DAq0J5dGVBcnJQcm9wxAMBAgM="), binary: "lQGAwKZtZXRob2STKqZzdHJpbmeGqlN0cmluZ1Byb3CoU2lnbmFsUiGqRG91YmxlUHJvcMtAGSH7VELPEqdJbnRQcm9wKqxEYXRlVGltZVByb3DW/1jsHICoTnVsbFByb3DAq0J5dGVBcnJQcm9wxAMBAgM="),
new ProtocolTestData( new ProtocolTestData(
name: "InvocationWithNoHeadersNoIdAndArrayOfCustomObjectArgs", name: "InvocationWithNoHeadersNoIdAndArrayOfCustomObjectArgs",
message: new InvocationMessage("method", null, new object[] { new CustomObject(), new CustomObject() }), message: new InvocationMessage("method", new object[] { new CustomObject(), new CustomObject() }),
binary: "lQGAwKZtZXRob2SShqpTdHJpbmdQcm9wqFNpZ25hbFIhqkRvdWJsZVByb3DLQBkh+1RCzxKnSW50UHJvcCqsRGF0ZVRpbWVQcm9w1v9Y7ByAqE51bGxQcm9wwKtCeXRlQXJyUHJvcMQDAQIDhqpTdHJpbmdQcm9wqFNpZ25hbFIhqkRvdWJsZVByb3DLQBkh+1RCzxKnSW50UHJvcCqsRGF0ZVRpbWVQcm9w1v9Y7ByAqE51bGxQcm9wwKtCeXRlQXJyUHJvcMQDAQID"), binary: "lQGAwKZtZXRob2SShqpTdHJpbmdQcm9wqFNpZ25hbFIhqkRvdWJsZVByb3DLQBkh+1RCzxKnSW50UHJvcCqsRGF0ZVRpbWVQcm9w1v9Y7ByAqE51bGxQcm9wwKtCeXRlQXJyUHJvcMQDAQIDhqpTdHJpbmdQcm9wqFNpZ25hbFIhqkRvdWJsZVByb3DLQBkh+1RCzxKnSW50UHJvcCqsRGF0ZVRpbWVQcm9w1v9Y7ByAqE51bGxQcm9wwKtCeXRlQXJyUHJvcMQDAQID"),
new ProtocolTestData( new ProtocolTestData(
name: "InvocationWithHeadersNoIdAndArrayOfCustomObjectArgs", name: "InvocationWithHeadersNoIdAndArrayOfCustomObjectArgs",
message: AddHeaders(TestHeaders, new InvocationMessage("method", null, new object[] { new CustomObject(), new CustomObject() })), message: AddHeaders(TestHeaders, new InvocationMessage("method", new object[] { new CustomObject(), new CustomObject() })),
binary: "lQGDo0Zvb6NCYXKyS2V5V2l0aApOZXcNCkxpbmVzq1N0aWxsIFdvcmtzsVZhbHVlV2l0aE5ld0xpbmVzsEFsc28KV29ya3MNCkZpbmXApm1ldGhvZJKGqlN0cmluZ1Byb3CoU2lnbmFsUiGqRG91YmxlUHJvcMtAGSH7VELPEqdJbnRQcm9wKqxEYXRlVGltZVByb3DW/1jsHICoTnVsbFByb3DAq0J5dGVBcnJQcm9wxAMBAgOGqlN0cmluZ1Byb3CoU2lnbmFsUiGqRG91YmxlUHJvcMtAGSH7VELPEqdJbnRQcm9wKqxEYXRlVGltZVByb3DW/1jsHICoTnVsbFByb3DAq0J5dGVBcnJQcm9wxAMBAgM="), binary: "lQGDo0Zvb6NCYXKyS2V5V2l0aApOZXcNCkxpbmVzq1N0aWxsIFdvcmtzsVZhbHVlV2l0aE5ld0xpbmVzsEFsc28KV29ya3MNCkZpbmXApm1ldGhvZJKGqlN0cmluZ1Byb3CoU2lnbmFsUiGqRG91YmxlUHJvcMtAGSH7VELPEqdJbnRQcm9wKqxEYXRlVGltZVByb3DW/1jsHICoTnVsbFByb3DAq0J5dGVBcnJQcm9wxAMBAgOGqlN0cmluZ1Byb3CoU2lnbmFsUiGqRG91YmxlUHJvcMtAGSH7VELPEqdJbnRQcm9wKqxEYXRlVGltZVByb3DW/1jsHICoTnVsbFByb3DAq0J5dGVBcnJQcm9wxAMBAgM="),
// StreamItem Messages // StreamItem Messages
@ -187,35 +187,35 @@ namespace Microsoft.AspNetCore.SignalR.Common.Tests.Internal.Protocol
// StreamInvocation Messages // StreamInvocation Messages
new ProtocolTestData( new ProtocolTestData(
name: "StreamInvocationWithNoHeadersAndNoArgs", name: "StreamInvocationWithNoHeadersAndNoArgs",
message: new StreamInvocationMessage("xyz", "method", null, Array.Empty<object>()), message: new StreamInvocationMessage("xyz", "method", Array.Empty<object>()),
binary: "lQSAo3h5eqZtZXRob2SQ"), binary: "lQSAo3h5eqZtZXRob2SQ"),
new ProtocolTestData( new ProtocolTestData(
name: "StreamInvocationWithNoHeadersAndNullArg", name: "StreamInvocationWithNoHeadersAndNullArg",
message: new StreamInvocationMessage("xyz", "method", null, new object[] { null }), message: new StreamInvocationMessage("xyz", "method", new object[] { null }),
binary: "lQSAo3h5eqZtZXRob2SRwA=="), binary: "lQSAo3h5eqZtZXRob2SRwA=="),
new ProtocolTestData( new ProtocolTestData(
name: "StreamInvocationWithNoHeadersAndIntArg", name: "StreamInvocationWithNoHeadersAndIntArg",
message: new StreamInvocationMessage("xyz", "method", null, new object[] { 42 }), message: new StreamInvocationMessage("xyz", "method", new object[] { 42 }),
binary: "lQSAo3h5eqZtZXRob2SRKg=="), binary: "lQSAo3h5eqZtZXRob2SRKg=="),
new ProtocolTestData( new ProtocolTestData(
name: "StreamInvocationWithNoHeadersAndEnumArg", name: "StreamInvocationWithNoHeadersAndEnumArg",
message: new StreamInvocationMessage("xyz", "method", null, new object[] { TestEnum.One }), message: new StreamInvocationMessage("xyz", "method", new object[] { TestEnum.One }),
binary: "lQSAo3h5eqZtZXRob2SRo09uZQ=="), binary: "lQSAo3h5eqZtZXRob2SRo09uZQ=="),
new ProtocolTestData( new ProtocolTestData(
name: "StreamInvocationWithNoHeadersAndIntAndStringArgs", name: "StreamInvocationWithNoHeadersAndIntAndStringArgs",
message: new StreamInvocationMessage("xyz", "method", null, new object[] { 42, "string" }), message: new StreamInvocationMessage("xyz", "method", new object[] { 42, "string" }),
binary: "lQSAo3h5eqZtZXRob2SSKqZzdHJpbmc="), binary: "lQSAo3h5eqZtZXRob2SSKqZzdHJpbmc="),
new ProtocolTestData( new ProtocolTestData(
name: "StreamInvocationWithNoHeadersAndIntStringAndCustomObjectArgs", name: "StreamInvocationWithNoHeadersAndIntStringAndCustomObjectArgs",
message: new StreamInvocationMessage("xyz", "method", null, new object[] { 42, "string", new CustomObject() }), message: new StreamInvocationMessage("xyz", "method", new object[] { 42, "string", new CustomObject() }),
binary: "lQSAo3h5eqZtZXRob2STKqZzdHJpbmeGqlN0cmluZ1Byb3CoU2lnbmFsUiGqRG91YmxlUHJvcMtAGSH7VELPEqdJbnRQcm9wKqxEYXRlVGltZVByb3DW/1jsHICoTnVsbFByb3DAq0J5dGVBcnJQcm9wxAMBAgM="), binary: "lQSAo3h5eqZtZXRob2STKqZzdHJpbmeGqlN0cmluZ1Byb3CoU2lnbmFsUiGqRG91YmxlUHJvcMtAGSH7VELPEqdJbnRQcm9wKqxEYXRlVGltZVByb3DW/1jsHICoTnVsbFByb3DAq0J5dGVBcnJQcm9wxAMBAgM="),
new ProtocolTestData( new ProtocolTestData(
name: "StreamInvocationWithNoHeadersAndCustomObjectArrayArg", name: "StreamInvocationWithNoHeadersAndCustomObjectArrayArg",
message: new StreamInvocationMessage("xyz", "method", null, new object[] { new CustomObject(), new CustomObject() }), message: new StreamInvocationMessage("xyz", "method", new object[] { new CustomObject(), new CustomObject() }),
binary: "lQSAo3h5eqZtZXRob2SShqpTdHJpbmdQcm9wqFNpZ25hbFIhqkRvdWJsZVByb3DLQBkh+1RCzxKnSW50UHJvcCqsRGF0ZVRpbWVQcm9w1v9Y7ByAqE51bGxQcm9wwKtCeXRlQXJyUHJvcMQDAQIDhqpTdHJpbmdQcm9wqFNpZ25hbFIhqkRvdWJsZVByb3DLQBkh+1RCzxKnSW50UHJvcCqsRGF0ZVRpbWVQcm9w1v9Y7ByAqE51bGxQcm9wwKtCeXRlQXJyUHJvcMQDAQID"), binary: "lQSAo3h5eqZtZXRob2SShqpTdHJpbmdQcm9wqFNpZ25hbFIhqkRvdWJsZVByb3DLQBkh+1RCzxKnSW50UHJvcCqsRGF0ZVRpbWVQcm9w1v9Y7ByAqE51bGxQcm9wwKtCeXRlQXJyUHJvcMQDAQIDhqpTdHJpbmdQcm9wqFNpZ25hbFIhqkRvdWJsZVByb3DLQBkh+1RCzxKnSW50UHJvcCqsRGF0ZVRpbWVQcm9w1v9Y7ByAqE51bGxQcm9wwKtCeXRlQXJyUHJvcMQDAQID"),
new ProtocolTestData( new ProtocolTestData(
name: "StreamInvocationWithHeadersAndCustomObjectArrayArg", name: "StreamInvocationWithHeadersAndCustomObjectArrayArg",
message: AddHeaders(TestHeaders, new StreamInvocationMessage("xyz", "method", null, new object[] { new CustomObject(), new CustomObject() })), message: AddHeaders(TestHeaders, new StreamInvocationMessage("xyz", "method", new object[] { new CustomObject(), new CustomObject() })),
binary: "lQSDo0Zvb6NCYXKyS2V5V2l0aApOZXcNCkxpbmVzq1N0aWxsIFdvcmtzsVZhbHVlV2l0aE5ld0xpbmVzsEFsc28KV29ya3MNCkZpbmWjeHl6pm1ldGhvZJKGqlN0cmluZ1Byb3CoU2lnbmFsUiGqRG91YmxlUHJvcMtAGSH7VELPEqdJbnRQcm9wKqxEYXRlVGltZVByb3DW/1jsHICoTnVsbFByb3DAq0J5dGVBcnJQcm9wxAMBAgOGqlN0cmluZ1Byb3CoU2lnbmFsUiGqRG91YmxlUHJvcMtAGSH7VELPEqdJbnRQcm9wKqxEYXRlVGltZVByb3DW/1jsHICoTnVsbFByb3DAq0J5dGVBcnJQcm9wxAMBAgM="), binary: "lQSDo0Zvb6NCYXKyS2V5V2l0aApOZXcNCkxpbmVzq1N0aWxsIFdvcmtzsVZhbHVlV2l0aE5ld0xpbmVzsEFsc28KV29ya3MNCkZpbmWjeHl6pm1ldGhvZJKGqlN0cmluZ1Byb3CoU2lnbmFsUiGqRG91YmxlUHJvcMtAGSH7VELPEqdJbnRQcm9wKqxEYXRlVGltZVByb3DW/1jsHICoTnVsbFByb3DAq0J5dGVBcnJQcm9wxAMBAgOGqlN0cmluZ1Byb3CoU2lnbmFsUiGqRG91YmxlUHJvcMtAGSH7VELPEqdJbnRQcm9wKqxEYXRlVGltZVByb3DW/1jsHICoTnVsbFByb3DAq0J5dGVBcnJQcm9wxAMBAgM="),
// CancelInvocation Messages // CancelInvocation Messages
@ -256,7 +256,7 @@ namespace Microsoft.AspNetCore.SignalR.Common.Tests.Internal.Protocol
[Fact] [Fact]
public void ParseMessageWithExtraData() public void ParseMessageWithExtraData()
{ {
var expectedMessage = new InvocationMessage("xyz", "method", null, Array.Empty<object>()); var expectedMessage = new InvocationMessage("xyz", "method", Array.Empty<object>());
// Verify that the input binary string decodes to the expected MsgPack primitives // Verify that the input binary string decodes to the expected MsgPack primitives
var bytes = new byte[] { ArrayBytes(6), 1, 0x80, StringBytes(3), (byte)'x', (byte)'y', (byte)'z', StringBytes(6), (byte)'m', (byte)'e', (byte)'t', (byte)'h', (byte)'o', (byte)'d', ArrayBytes(0), StringBytes(2), (byte)'e', (byte)'x' }; var bytes = new byte[] { ArrayBytes(6), 1, 0x80, StringBytes(3), (byte)'x', (byte)'y', (byte)'z', StringBytes(6), (byte)'m', (byte)'e', (byte)'t', (byte)'h', (byte)'o', (byte)'d', ArrayBytes(0), StringBytes(2), (byte)'e', (byte)'x' };
@ -422,9 +422,8 @@ namespace Microsoft.AspNetCore.SignalR.Common.Tests.Internal.Protocol
var binder = new TestBinder(new[] { typeof(string) }, typeof(string)); var binder = new TestBinder(new[] { typeof(string) }, typeof(string));
var data = new ReadOnlySequence<byte>(buffer); var data = new ReadOnlySequence<byte>(buffer);
_hubProtocol.TryParseMessage(ref data, binder, out var message); _hubProtocol.TryParseMessage(ref data, binder, out var message);
var exception = Assert.Throws<InvalidDataException>(() => ((HubMethodInvocationMessage)message).Arguments); var bindingFailure = Assert.IsType<InvocationBindingFailureMessage>(message);
Assert.Equal(testData.ErrorMessage, bindingFailure.BindingFailure.SourceException.Message);
Assert.Equal(testData.ErrorMessage, exception.Message);
} }
[Theory] [Theory]

View File

@ -84,12 +84,14 @@ namespace Microsoft.AspNetCore.SignalR.Redis.Tests
} }
// The actual invocation message doesn't matter // The actual invocation message doesn't matter
private static InvocationMessage _testMessage = new InvocationMessage("target", null, Array.Empty<object>()); private static InvocationMessage _testMessage = new InvocationMessage("target", Array.Empty<object>());
private static Dictionary<string, ProtocolTestData<RedisInvocation>> _invocationTestData = new[]
// We use a func so we are guaranteed to get a new SerializedHubMessage for each test
private static Dictionary<string, ProtocolTestData<Func<RedisInvocation>>> _invocationTestData = new[]
{ {
CreateTestData( CreateTestData<Func<RedisInvocation>>(
"NoExcludedIds", "NoExcludedIds",
new RedisInvocation(new SerializedHubMessage(_testMessage), null), () => new RedisInvocation(new SerializedHubMessage(_testMessage), null),
0x92, 0x92,
0x90, 0x90,
0x82, 0x82,
@ -97,9 +99,9 @@ namespace Microsoft.AspNetCore.SignalR.Redis.Tests
0xC4, 0x01, 0x2A, 0xC4, 0x01, 0x2A,
0xA2, (byte)'p', (byte)'2', 0xA2, (byte)'p', (byte)'2',
0xC4, 0x01, 0x2A), 0xC4, 0x01, 0x2A),
CreateTestData( CreateTestData<Func<RedisInvocation>>(
"OneExcludedId", "OneExcludedId",
new RedisInvocation(new SerializedHubMessage(_testMessage), new [] { "a" }), () => new RedisInvocation(new SerializedHubMessage(_testMessage), new [] { "a" }),
0x92, 0x92,
0x91, 0x91,
0xA1, (byte)'a', 0xA1, (byte)'a',
@ -108,9 +110,9 @@ namespace Microsoft.AspNetCore.SignalR.Redis.Tests
0xC4, 0x01, 0x2A, 0xC4, 0x01, 0x2A,
0xA2, (byte)'p', (byte)'2', 0xA2, (byte)'p', (byte)'2',
0xC4, 0x01, 0x2A), 0xC4, 0x01, 0x2A),
CreateTestData( CreateTestData<Func<RedisInvocation>>(
"ManyExcludedIds", "ManyExcludedIds",
new RedisInvocation(new SerializedHubMessage(_testMessage), new [] { "a", "b", "c", "d", "e", "f" }), () => new RedisInvocation(new SerializedHubMessage(_testMessage), new [] { "a", "b", "c", "d", "e", "f" }),
0x92, 0x92,
0x96, 0x96,
0xA1, (byte)'a', 0xA1, (byte)'a',
@ -136,15 +138,17 @@ namespace Microsoft.AspNetCore.SignalR.Redis.Tests
var hubProtocols = new[] { new DummyHubProtocol("p1"), new DummyHubProtocol("p2") }; var hubProtocols = new[] { new DummyHubProtocol("p1"), new DummyHubProtocol("p2") };
var protocol = new RedisProtocol(hubProtocols); var protocol = new RedisProtocol(hubProtocols);
var expected = testData.Decoded();
var decoded = protocol.ReadInvocation(testData.Encoded); var decoded = protocol.ReadInvocation(testData.Encoded);
Assert.Equal(testData.Decoded.ExcludedConnectionIds, decoded.ExcludedConnectionIds); Assert.Equal(expected.ExcludedConnectionIds, decoded.ExcludedConnectionIds);
// Verify the deserialized object has the necessary serialized forms // Verify the deserialized object has the necessary serialized forms
foreach (var hubProtocol in hubProtocols) foreach (var hubProtocol in hubProtocols)
{ {
Assert.Equal( Assert.Equal(
testData.Decoded.Message.GetSerializedMessage(hubProtocol).ToArray(), expected.Message.GetSerializedMessage(hubProtocol).ToArray(),
decoded.Message.GetSerializedMessage(hubProtocol).ToArray()); decoded.Message.GetSerializedMessage(hubProtocol).ToArray());
Assert.Equal(1, hubProtocol.SerializationCount); Assert.Equal(1, hubProtocol.SerializationCount);
} }
@ -159,7 +163,8 @@ namespace Microsoft.AspNetCore.SignalR.Redis.Tests
// Actual invocation doesn't matter because we're using a dummy hub protocol. // Actual invocation doesn't matter because we're using a dummy hub protocol.
// But the dummy protocol will check that we gave it the test message to make sure everything flows through properly. // But the dummy protocol will check that we gave it the test message to make sure everything flows through properly.
var encoded = protocol.WriteInvocation(_testMessage.Target, _testMessage.Arguments, testData.Decoded.ExcludedConnectionIds); var expected = testData.Decoded();
var encoded = protocol.WriteInvocation(_testMessage.Target, _testMessage.Arguments, expected.ExcludedConnectionIds);
Assert.Equal(testData.Encoded, encoded); Assert.Equal(testData.Encoded, encoded);
} }

View File

@ -164,13 +164,13 @@ namespace Microsoft.AspNetCore.SignalR.Tests
public Task<string> SendInvocationAsync(string methodName, bool nonBlocking, params object[] args) public Task<string> SendInvocationAsync(string methodName, bool nonBlocking, params object[] args)
{ {
var invocationId = nonBlocking ? null : GetInvocationId(); var invocationId = nonBlocking ? null : GetInvocationId();
return SendHubMessageAsync(new InvocationMessage(invocationId, methodName, null, args)); return SendHubMessageAsync(new InvocationMessage(invocationId, methodName, args));
} }
public Task<string> SendStreamInvocationAsync(string methodName, params object[] args) public Task<string> SendStreamInvocationAsync(string methodName, params object[] args)
{ {
var invocationId = GetInvocationId(); var invocationId = GetInvocationId();
return SendHubMessageAsync(new StreamInvocationMessage(invocationId, methodName, null, args)); return SendHubMessageAsync(new StreamInvocationMessage(invocationId, methodName, args));
} }
public async Task<string> SendHubMessageAsync(HubMessage message) public async Task<string> SendHubMessageAsync(HubMessage message)

View File

@ -1429,7 +1429,7 @@ namespace Microsoft.AspNetCore.SignalR.Tests
await client.Connected.OrTimeout(); await client.Connected.OrTimeout();
var invocationId = Guid.NewGuid().ToString("N"); var invocationId = Guid.NewGuid().ToString("N");
await client.SendHubMessageAsync(new StreamInvocationMessage(invocationId, nameof(StreamingHub.BlockingStream), null, Array.Empty<object>())); await client.SendHubMessageAsync(new StreamInvocationMessage(invocationId, nameof(StreamingHub.BlockingStream), Array.Empty<object>()));
// cancel the Streaming method // cancel the Streaming method
await client.SendHubMessageAsync(new CancelInvocationMessage(invocationId)).OrTimeout(); await client.SendHubMessageAsync(new CancelInvocationMessage(invocationId)).OrTimeout();

View File

@ -1,29 +0,0 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System;
using System.Runtime.ExceptionServices;
using Microsoft.AspNetCore.SignalR.Protocol;
using Xunit;
namespace Microsoft.AspNetCore.SignalR.Tests
{
public class HubMethodInvocationMessageTests
{
[Fact]
public void InvocationMessageToStringPutsErrorInArgs()
{
var hubMessage = new InvocationMessage("echo", ExceptionDispatchInfo.Capture(new Exception("test")), null);
Assert.Equal("InvocationMessage { InvocationId: \"\", Target: \"echo\", Arguments: [ Error: test ] }", hubMessage.ToString());
}
[Fact]
public void StreamInvocationMessageToStringPutsErrorInArgs()
{
var hubMessage = new StreamInvocationMessage("3", "echo", ExceptionDispatchInfo.Capture(new Exception("test")), null);
Assert.Equal("StreamInvocation { InvocationId: \"3\", Target: \"echo\", Arguments: [ Error: test ] }", hubMessage.ToString());
}
}
}