private static StreamCompletionMessage CreateStreamCompletionMessage(Unpacker unpacker, long arraySize, IInvocationBinder binder) { Debug.Assert(arraySize == 2 || arraySize == 3, "Unexpected item count"); var invocationId = ReadInvocationId(unpacker); // Error is optional so StreamCompletion without error has 2 items, StreamCompletion with error has 3 items var error = arraySize == 3 ? ReadString(unpacker, "error") : null; return(new StreamCompletionMessage(invocationId, error)); }
private HubMessage CreateStreamInvocationMessage(ref MessagePackReader reader, IInvocationBinder binder, int itemCount) { var headers = ReadHeaders(ref reader); var invocationId = ReadInvocationId(ref reader); var target = ReadString(ref reader, "target"); object[] arguments; try { var parameterTypes = binder.GetParameterTypes(target); arguments = BindArguments(ref reader, parameterTypes); } catch (Exception ex) { return(new InvocationBindingFailureMessage(invocationId, target, ExceptionDispatchInfo.Capture(ex))); } string[]? streams = null; // Previous clients will send 5 items, so we check if they sent a stream array or not if (itemCount > 5) { streams = ReadStreamIds(ref reader); } return(ApplyHeaders(headers, new StreamInvocationMessage(invocationId, target, arguments, streams))); }
private static StreamInvocationMessage CreateStreamInvocationMessage(Unpacker unpacker, IInvocationBinder binder) { var headers = ReadHeaders(unpacker); var invocationId = ReadInvocationId(unpacker); var target = ReadString(unpacker, "target"); var parameterTypes = binder.GetParameterTypes(target); try { var arguments = BindArguments(unpacker, parameterTypes); return(ApplyHeaders(headers, new StreamInvocationMessage(invocationId, target, argumentBindingException: null, arguments: arguments))); } catch (Exception ex) { return(ApplyHeaders(headers, new StreamInvocationMessage(invocationId, target, ExceptionDispatchInfo.Capture(ex)))); } }
public bool TryParseMessage(ref ReadOnlySequence <byte> input, IInvocationBinder binder, out HubMessage message) { throw new NotSupportedException(); }
private static HubMessage CreateStreamItemMessage(ref MessagePackReader reader, IInvocationBinder binder, MessagePackSerializerOptions msgPackSerializerOptions) { var headers = ReadHeaders(ref reader); var invocationId = ReadInvocationId(ref reader); object value; try { var itemType = binder.GetStreamItemType(invocationId); value = DeserializeObject(ref reader, itemType, "item", msgPackSerializerOptions); } catch (Exception ex) { return(new StreamBindingFailureMessage(invocationId, ExceptionDispatchInfo.Capture(ex))); } return(ApplyHeaders(headers, new StreamItemMessage(invocationId, value))); }
private static HubMessage BindCompletionMessage(string invocationId, string?error, object?result, bool hasResult, IInvocationBinder binder) { if (string.IsNullOrEmpty(invocationId)) { throw new InvalidDataException($"Missing required property '{InvocationIdPropertyName}'."); } if (error != null && hasResult) { throw new InvalidDataException("The 'error' and 'result' properties are mutually exclusive."); } if (hasResult) { return(new CompletionMessage(invocationId, error, result, hasResult: true)); } return(new CompletionMessage(invocationId, error, result: null, hasResult: false)); }
private static HubMessage BindInvocationMessage(string?invocationId, string target, object?[]?arguments, bool hasArguments, string[]?streamIds, IInvocationBinder binder) { if (string.IsNullOrEmpty(target)) { throw new InvalidDataException($"Missing required property '{TargetPropertyName}'."); } if (!hasArguments) { throw new InvalidDataException($"Missing required property '{ArgumentsPropertyName}'."); } Debug.Assert(arguments != null); return(new InvocationMessage(invocationId, target, arguments, streamIds)); }
private static StreamInvocationMessage CreateStreamInvocationMessage(Unpacker unpacker, IInvocationBinder binder) { var invocationId = ReadInvocationId(unpacker); var metadata = ReadMetadata(unpacker); var target = ReadString(unpacker, "target"); var parameterTypes = binder.GetParameterTypes(target); try { var arguments = BindArguments(unpacker, parameterTypes); return(new StreamInvocationMessage(invocationId, metadata, target, arguments: arguments)); } catch (Exception ex) { return(new StreamInvocationMessage(invocationId, metadata, target, ExceptionDispatchInfo.Capture(ex))); } }
public HubMessageReader(IHubProtocol hubProtocol, IInvocationBinder invocationBinder) { _hubProtocol = hubProtocol; _invocationBinder = invocationBinder; }
private HubMessage BindParamStreamMessage(string streamId, object item, bool hasItem, IInvocationBinder binder) { if (string.IsNullOrEmpty(streamId)) { throw new InvalidDataException($"Missing required property '{StreamIdPropertyName}"); } if (!hasItem) { throw new InvalidDataException($"Missing required property '{ItemPropertyName}"); } return(new StreamDataMessage(streamId, item)); }
private static HubMessage ParseBroadcastDataMessageJson(BroadcastDataMessage bdm, IInvocationBinder binder) { foreach (var payload in bdm.Payloads) { if (payload.Key == "json") { var sequence = new ReadOnlySequence <byte>(payload.Value); if (_signalRPro.TryParseMessage(ref sequence, binder, out var signalRRRmessage)) { return(signalRRRmessage); } } } return(null); }
private static StreamItemMessage CreateStreamItemMessage(ref MessagePackReader reader, IInvocationBinder binder) { var headers = ReadHeaders(ref reader); var invocationId = ReadString(ref reader, "invocationId"); var itemType = binder.GetStreamItemType(invocationId); var value = DeserializeObject(ref reader, itemType, "item"); return(ApplyHeaders(headers, new StreamItemMessage(invocationId, value))); }
private static HubMessage ParseBroadcastDataMessageJson(BroadcastDataMessage bdm, IInvocationBinder binder) { foreach (var payload in bdm.Payloads) { if (payload.Key == "json") { var sequence = new ReadOnlySequence <byte>(payload.Value); if (_signalRPro.TryParseMessage(ref sequence, binder, out var signalRRRmessage)) { if (signalRRRmessage is InvocationMessage inv) { Console.WriteLine($" -- {bdm}: callback# {inv.Target} {inv.Arguments[0]}"); } else { Console.WriteLine($"oh something else {signalRRRmessage}"); } return(signalRRRmessage); } else { Console.WriteLine("failed.."); } }
public bool ReadMessages(byte[] input, IInvocationBinder binder, out IList <HubMessage> messages) { var buffer = _dataEncoder.Decode(input); return(_hubProtocol.TryParseMessages(buffer, binder, out messages)); }
private HubMessage BindStreamInvocationMessage(string invocationId, string target, object[] arguments, bool hasArguments, string[] streamIds, IInvocationBinder binder) { if (string.IsNullOrEmpty(invocationId)) { throw new InvalidDataException($"Missing required property '{InvocationIdPropertyName}'."); } if (!hasArguments) { throw new InvalidDataException($"Missing required property '{ArgumentsPropertyName}'."); } if (string.IsNullOrEmpty(target)) { throw new InvalidDataException($"Missing required property '{TargetPropertyName}'."); } return(new StreamInvocationMessage(invocationId, target, arguments, streamIds)); }
public TestClient(bool synchronousCallbacks = false, IHubProtocol protocol = null, IInvocationBinder invocationBinder = null, bool addClaimId = false) { var options = new PipeOptions(readerScheduler: synchronousCallbacks ? PipeScheduler.Inline : null); var pair = DuplexPipe.CreateConnectionPair(options, options); Connection = new DefaultConnectionContext(Guid.NewGuid().ToString(), pair.Transport, pair.Application); var claimValue = Interlocked.Increment(ref _id).ToString(); var claims = new List <Claim> { new Claim(ClaimTypes.Name, claimValue) }; if (addClaimId) { claims.Add(new Claim(ClaimTypes.NameIdentifier, claimValue)); } Connection.User = new ClaimsPrincipal(new ClaimsIdentity(claims)); Connection.Metadata["ConnectedTask"] = new TaskCompletionSource <bool>(); _protocol = protocol ?? new JsonHubProtocol(); _invocationBinder = invocationBinder ?? new DefaultInvocationBinder(); _cts = new CancellationTokenSource(); using (var memoryStream = new MemoryStream()) { NegotiationProtocol.WriteMessage(new NegotiationMessage(_protocol.Name), memoryStream); Connection.Application.Output.WriteAsync(memoryStream.ToArray()); } }
private HubMessage?ParseMessage(Utf8BufferTextReader textReader, IInvocationBinder binder) { try { // We parse using the JsonTextReader directly but this has a problem. Some of our properties are dependent on other properties // and since reading the json might be unordered, we need to store the parsed content as JToken to re-parse when true types are known. // if we're lucky and the state we need to directly parse is available, then we'll use it. int? type = null; string? invocationId = null; string? target = null; string? error = null; var hasItem = false; object? item = null; JToken? itemToken = null; var hasResult = false; object? result = null; JToken? resultToken = null; var hasArguments = false; object?[]? arguments = null; string[]? streamIds = null; JArray?argumentsToken = null; ExceptionDispatchInfo? argumentBindingException = null; Dictionary <string, string>?headers = null; var completed = false; var allowReconnect = false; using (var reader = JsonUtils.CreateJsonTextReader(textReader)) { reader.DateParseHandling = DateParseHandling.None; JsonUtils.CheckRead(reader); // We're always parsing a JSON object JsonUtils.EnsureObjectStart(reader); do { switch (reader.TokenType) { case JsonToken.PropertyName: var memberName = reader.Value?.ToString(); switch (memberName) { case TypePropertyName: var messageType = JsonUtils.ReadAsInt32(reader, TypePropertyName); if (messageType == null) { throw new InvalidDataException($"Missing required property '{TypePropertyName}'."); } type = messageType.Value; break; case InvocationIdPropertyName: invocationId = JsonUtils.ReadAsString(reader, InvocationIdPropertyName); break; case StreamIdsPropertyName: JsonUtils.CheckRead(reader); if (reader.TokenType != JsonToken.StartArray) { throw new InvalidDataException($"Expected '{StreamIdsPropertyName}' to be of type {JTokenType.Array}."); } var newStreamIds = new List <string>(); reader.Read(); while (reader.TokenType != JsonToken.EndArray) { newStreamIds.Add(reader.Value?.ToString() ?? throw new InvalidDataException($"Null value for '{StreamIdsPropertyName}' is not valid.")); reader.Read(); } streamIds = newStreamIds.ToArray(); break; case TargetPropertyName: target = JsonUtils.ReadAsString(reader, TargetPropertyName); break; case ErrorPropertyName: error = JsonUtils.ReadAsString(reader, ErrorPropertyName); break; case AllowReconnectPropertyName: allowReconnect = JsonUtils.ReadAsBoolean(reader, AllowReconnectPropertyName); break; case ResultPropertyName: hasResult = true; if (string.IsNullOrEmpty(invocationId)) { JsonUtils.CheckRead(reader); // If we don't have an invocation id then we need to store it as a JToken so we can parse it later resultToken = JToken.Load(reader); } else { // If we have an invocation id already we can parse the end result var returnType = binder.GetReturnType(invocationId); if (!JsonUtils.ReadForType(reader, returnType)) { throw new JsonReaderException("Unexpected end when reading JSON"); } result = PayloadSerializer.Deserialize(reader, returnType); } break; case ItemPropertyName: JsonUtils.CheckRead(reader); hasItem = true; string?id = null; if (!string.IsNullOrEmpty(invocationId)) { id = invocationId; } else { // If we don't have an id yet then we need to store it as a JToken to parse later itemToken = JToken.Load(reader); break; } try { var itemType = binder.GetStreamItemType(id); item = PayloadSerializer.Deserialize(reader, itemType); } catch (Exception ex) { return(new StreamBindingFailureMessage(id, ExceptionDispatchInfo.Capture(ex))); } break; case ArgumentsPropertyName: JsonUtils.CheckRead(reader); int initialDepth = reader.Depth; if (reader.TokenType != JsonToken.StartArray) { throw new InvalidDataException($"Expected '{ArgumentsPropertyName}' to be of type {JTokenType.Array}."); } hasArguments = true; if (string.IsNullOrEmpty(target)) { // We don't know the method name yet so just parse an array of generic JArray argumentsToken = JArray.Load(reader); } else { try { var paramTypes = binder.GetParameterTypes(target); arguments = BindArguments(reader, paramTypes); } catch (Exception ex) { argumentBindingException = ExceptionDispatchInfo.Capture(ex); // Could be at any point in argument array JSON when an error is thrown // Read until the end of the argument JSON array while (reader.Depth == initialDepth && reader.TokenType == JsonToken.StartArray || reader.Depth > initialDepth) { JsonUtils.CheckRead(reader); } } } break; case HeadersPropertyName: JsonUtils.CheckRead(reader); headers = ReadHeaders(reader); break; default: // Skip read the property name JsonUtils.CheckRead(reader); // Skip the value for this property reader.Skip(); break; } break; case JsonToken.EndObject: completed = true; break; } }while (!completed && JsonUtils.CheckRead(reader)); } HubMessage message; switch (type) { case HubProtocolConstants.InvocationMessageType: { if (target is null) { throw new InvalidDataException($"Missing required property '{TargetPropertyName}'."); } 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 { var paramTypes = binder.GetParameterTypes(target); arguments = BindArguments(argumentsToken, paramTypes); } catch (Exception ex) { argumentBindingException = ExceptionDispatchInfo.Capture(ex); } } message = argumentBindingException != null ? new InvocationBindingFailureMessage(invocationId, target, argumentBindingException) : BindInvocationMessage(invocationId, target, arguments, hasArguments, streamIds, binder); } break; case HubProtocolConstants.StreamInvocationMessageType: { if (target is null) { throw new InvalidDataException($"Missing required property '{TargetPropertyName}'."); } 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 { var paramTypes = binder.GetParameterTypes(target); arguments = BindArguments(argumentsToken, paramTypes); } catch (Exception ex) { argumentBindingException = ExceptionDispatchInfo.Capture(ex); } } message = argumentBindingException != null ? new InvocationBindingFailureMessage(invocationId, target, argumentBindingException) : BindStreamInvocationMessage(invocationId, target, arguments, hasArguments, streamIds, binder); } break; case HubProtocolConstants.StreamItemMessageType: if (invocationId is null) { throw new InvalidDataException($"Missing required property '{InvocationIdPropertyName}'."); } if (itemToken != null) { try { var itemType = binder.GetStreamItemType(invocationId); item = itemToken.ToObject(itemType, PayloadSerializer); } catch (Exception ex) { message = new StreamBindingFailureMessage(invocationId, ExceptionDispatchInfo.Capture(ex)); break; }; } message = BindStreamItemMessage(invocationId, item, hasItem, binder); break; case HubProtocolConstants.CompletionMessageType: if (invocationId is null) { throw new InvalidDataException($"Missing required property '{InvocationIdPropertyName}'."); } if (resultToken != null) { var returnType = binder.GetReturnType(invocationId); result = resultToken.ToObject(returnType, PayloadSerializer); } message = BindCompletionMessage(invocationId, error, result, hasResult, binder); break; case HubProtocolConstants.CancelInvocationMessageType: message = BindCancelInvocationMessage(invocationId); break; case HubProtocolConstants.PingMessageType: return(PingMessage.Instance); case HubProtocolConstants.CloseMessageType: return(BindCloseMessage(error, allowReconnect)); case null: throw new InvalidDataException($"Missing required property '{TypePropertyName}'."); default: // Future protocol changes can add message types, old clients can ignore them return(null); } return(ApplyHeaders(message, headers)); } catch (JsonReaderException jrex) { throw new InvalidDataException("Error reading JSON.", jrex); } }
public TestClient(bool synchronousCallbacks = false, IHubProtocol protocol = null, IInvocationBinder invocationBinder = null, bool addClaimId = false) { var pair = DuplexPipePair.GetConnectionTransport(synchronousCallbacks); Connection = new DefaultConnectionContext(Guid.NewGuid().ToString(), pair.Transport, pair.Application); // Add features SignalR needs for testing Connection.Features.Set <ITransferFormatFeature>(this); Connection.Features.Set <IConnectionHeartbeatFeature>(this); var claimValue = Interlocked.Increment(ref _id).ToString(); var claims = new List <Claim> { new Claim(ClaimTypes.Name, claimValue) }; if (addClaimId) { claims.Add(new Claim(ClaimTypes.NameIdentifier, claimValue)); } Connection.User = new ClaimsPrincipal(new ClaimsIdentity(claims)); Connection.Items["ConnectedTask"] = new TaskCompletionSource <bool>(); _protocol = protocol ?? new JsonHubProtocol(); _invocationBinder = invocationBinder ?? new DefaultInvocationBinder(); _cts = new CancellationTokenSource(); }
private static HubMessage BindStreamItemMessage(string invocationId, object?item, bool hasItem, IInvocationBinder binder) { if (string.IsNullOrEmpty(invocationId)) { throw new InvalidDataException($"Missing required property '{InvocationIdPropertyName}'."); } if (!hasItem) { throw new InvalidDataException($"Missing required property '{ItemPropertyName}'."); } return(new StreamItemMessage(invocationId, item)); }
public bool TryParseMessage(ref ReadOnlySequence <byte> input, IInvocationBinder binder, out HubMessage message) { return(_innerProtocol.TryParseMessage(ref input, binder, out message)); }
/// <inheritdoc /> public bool TryParseMessage(ref ReadOnlySequence <byte> input, IInvocationBinder binder, out HubMessage message) => _worker.TryParseMessage(ref input, binder, out message);
public bool TryParseMessages(ReadOnlySpan <byte> input, IInvocationBinder binder, IList <HubMessage> messages) { return(false); }
private static HubMessage CreateInvocationMessage(ref MessagePackReader reader, IInvocationBinder binder, MessagePackSerializerOptions msgPackSerializerOptions, int itemCount) { var headers = ReadHeaders(ref reader); var invocationId = ReadInvocationId(ref reader); // For MsgPack, we represent an empty invocation ID as an empty string, // so we need to normalize that to "null", which is what indicates a non-blocking invocation. if (string.IsNullOrEmpty(invocationId)) { invocationId = null; } var target = ReadString(ref reader, "target"); object[] arguments = null; try { var parameterTypes = binder.GetParameterTypes(target); arguments = BindArguments(ref reader, parameterTypes, msgPackSerializerOptions); } catch (Exception ex) { return(new InvocationBindingFailureMessage(invocationId, target, ExceptionDispatchInfo.Capture(ex))); } string[] streams = null; // Previous clients will send 5 items, so we check if they sent a stream array or not if (itemCount > 5) { streams = ReadStreamIds(ref reader); } return(ApplyHeaders(headers, new InvocationMessage(invocationId, target, arguments, streams))); }
private HubMessage ParseMessage(ReadOnlySequence <byte> input, IInvocationBinder binder) { try { // We parse using the Utf8JsonReader directly but this has a problem. Some of our properties are dependent on other properties // and since reading the json might be unordered, we need to store the parsed content as JsonDocument to re-parse when true types are known. // if we're lucky and the state we need to directly parse is available, then we'll use it. int? type = null; string invocationId = null; string target = null; string error = null; var hasItem = false; object item = null; var hasResult = false; object result = null; var hasArguments = false; object[] arguments = null; string[] streamIds = null; bool hasArgumentsToken = false; Utf8JsonReader argumentsToken = default; bool hasItemsToken = false; Utf8JsonReader itemsToken = default; bool hasResultToken = false; Utf8JsonReader resultToken = default; ExceptionDispatchInfo argumentBindingException = null; Dictionary <string, string> headers = null; var completed = false; var reader = new Utf8JsonReader(input, isFinalBlock: true, state: default); reader.CheckRead(); // We're always parsing a JSON object reader.EnsureObjectStart(); do { switch (reader.TokenType) { case JsonTokenType.PropertyName: if (reader.ValueTextEquals(TypePropertyNameBytes.EncodedUtf8Bytes)) { type = reader.ReadAsInt32(TypePropertyName); if (type == null) { throw new InvalidDataException($"Expected '{TypePropertyName}' to be of type {JsonTokenType.Number}."); } } else if (reader.ValueTextEquals(InvocationIdPropertyNameBytes.EncodedUtf8Bytes)) { invocationId = reader.ReadAsString(InvocationIdPropertyName); } else if (reader.ValueTextEquals(StreamIdsPropertyNameBytes.EncodedUtf8Bytes)) { reader.CheckRead(); if (reader.TokenType != JsonTokenType.StartArray) { throw new InvalidDataException( $"Expected '{StreamIdsPropertyName}' to be of type {SystemTextJsonExtensions.GetTokenString(JsonTokenType.StartArray)}."); } var newStreamIds = new List <string>(); reader.Read(); while (reader.TokenType != JsonTokenType.EndArray) { newStreamIds.Add(reader.GetString()); reader.Read(); } streamIds = newStreamIds.ToArray(); } else if (reader.ValueTextEquals(TargetPropertyNameBytes.EncodedUtf8Bytes)) { target = reader.ReadAsString(TargetPropertyName); } else if (reader.ValueTextEquals(ErrorPropertyNameBytes.EncodedUtf8Bytes)) { error = reader.ReadAsString(ErrorPropertyName); } else if (reader.ValueTextEquals(ResultPropertyNameBytes.EncodedUtf8Bytes)) { hasResult = true; reader.CheckRead(); if (string.IsNullOrEmpty(invocationId)) { // If we don't have an invocation id then we need to value copy the reader so we can parse it later hasResultToken = true; resultToken = reader; reader.Skip(); } else { // If we have an invocation id already we can parse the end result var returnType = binder.GetReturnType(invocationId); result = BindType(ref reader, returnType); } } else if (reader.ValueTextEquals(ItemPropertyNameBytes.EncodedUtf8Bytes)) { reader.CheckRead(); hasItem = true; string id = null; if (!string.IsNullOrEmpty(invocationId)) { id = invocationId; } else { // If we don't have an id yet then we need to value copy the reader so we can parse it later hasItemsToken = true; itemsToken = reader; reader.Skip(); continue; } try { var itemType = binder.GetStreamItemType(id); item = BindType(ref reader, itemType); } catch (Exception ex) { return(new StreamBindingFailureMessage(id, ExceptionDispatchInfo.Capture(ex))); } } else if (reader.ValueTextEquals(ArgumentsPropertyNameBytes.EncodedUtf8Bytes)) { reader.CheckRead(); int initialDepth = reader.CurrentDepth; if (reader.TokenType != JsonTokenType.StartArray) { throw new InvalidDataException($"Expected '{ArgumentsPropertyName}' to be of type {SystemTextJsonExtensions.GetTokenString(JsonTokenType.StartArray)}."); } hasArguments = true; if (string.IsNullOrEmpty(target)) { // We don't know the method name yet so just value copy the reader so we can parse it later hasArgumentsToken = true; argumentsToken = reader; reader.Skip(); } else { try { var paramTypes = binder.GetParameterTypes(target); arguments = BindTypes(ref reader, paramTypes); } catch (Exception ex) { argumentBindingException = ExceptionDispatchInfo.Capture(ex); // Could be at any point in argument array JSON when an error is thrown // Read until the end of the argument JSON array while (reader.CurrentDepth == initialDepth && reader.TokenType == JsonTokenType.StartArray || reader.CurrentDepth > initialDepth) { reader.CheckRead(); } } } } else if (reader.ValueTextEquals(HeadersPropertyNameBytes.EncodedUtf8Bytes)) { reader.CheckRead(); headers = ReadHeaders(ref reader); } else { reader.CheckRead(); reader.Skip(); } break; case JsonTokenType.EndObject: completed = true; break; } }while (!completed && reader.CheckRead()); HubMessage message; switch (type) { case HubProtocolConstants.InvocationMessageType: { if (hasArgumentsToken) { // 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 { var paramTypes = binder.GetParameterTypes(target); arguments = BindTypes(ref argumentsToken, paramTypes); } catch (Exception ex) { argumentBindingException = ExceptionDispatchInfo.Capture(ex); } } message = argumentBindingException != null ? new InvocationBindingFailureMessage(invocationId, target, argumentBindingException) : BindInvocationMessage(invocationId, target, arguments, hasArguments, streamIds, binder); } break; case HubProtocolConstants.StreamInvocationMessageType: { if (hasArgumentsToken) { // 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 { var paramTypes = binder.GetParameterTypes(target); arguments = BindTypes(ref argumentsToken, paramTypes); } catch (Exception ex) { argumentBindingException = ExceptionDispatchInfo.Capture(ex); } } message = argumentBindingException != null ? new InvocationBindingFailureMessage(invocationId, target, argumentBindingException) : BindStreamInvocationMessage(invocationId, target, arguments, hasArguments, streamIds, binder); } break; case HubProtocolConstants.StreamItemMessageType: if (hasItemsToken) { try { var returnType = binder.GetStreamItemType(invocationId); item = BindType(ref itemsToken, returnType); } catch (JsonException ex) { message = new StreamBindingFailureMessage(invocationId, ExceptionDispatchInfo.Capture(ex)); break; } } message = BindStreamItemMessage(invocationId, item, hasItem, binder); break; case HubProtocolConstants.CompletionMessageType: if (hasResultToken) { var returnType = binder.GetReturnType(invocationId); result = BindType(ref resultToken, returnType); } message = BindCompletionMessage(invocationId, error, result, hasResult, binder); break; case HubProtocolConstants.CancelInvocationMessageType: message = BindCancelInvocationMessage(invocationId); break; case HubProtocolConstants.PingMessageType: return(PingMessage.Instance); case HubProtocolConstants.CloseMessageType: return(BindCloseMessage(error)); case null: throw new InvalidDataException($"Missing required property '{TypePropertyName}'."); default: // Future protocol changes can add message types, old clients can ignore them return(null); } return(ApplyHeaders(message, headers)); } catch (JsonException jrex) { throw new InvalidDataException("Error reading JSON.", jrex); } }
public bool TryParseMessage(ref ReadOnlySequence<byte> input, IInvocationBinder binder, out HubMessage message) { message = null; return false; }
private HubMessage BindInvocationMessage(string invocationId, string target, ExceptionDispatchInfo argumentBindingException, object[] arguments, bool hasArguments, IInvocationBinder binder) { if (string.IsNullOrEmpty(target)) { throw new InvalidDataException($"Missing required property '{TargetPropertyName}'."); } if (!hasArguments) { throw new InvalidDataException($"Missing required property '{ArgumentsPropertyName}'."); } return(new InvocationMessage(invocationId, target, argumentBindingException: argumentBindingException, arguments: arguments)); }
private CompletionMessage CreateCompletionMessage(ref MessagePackReader reader, IInvocationBinder binder) { var headers = ReadHeaders(ref reader); var invocationId = ReadInvocationId(ref reader); var resultKind = ReadInt32(ref reader, "resultKind"); string?error = null; object?result = null; var hasResult = false; switch (resultKind) { case ErrorResult: error = ReadString(ref reader, "error"); break; case NonVoidResult: var itemType = binder.GetReturnType(invocationId); result = DeserializeObject(ref reader, itemType, "argument"); hasResult = true; break; case VoidResult: hasResult = false; break; default: throw new InvalidDataException("Invalid invocation result kind."); } return(ApplyHeaders(headers, new CompletionMessage(invocationId, error, result, hasResult))); }
private HubMessage ParseMessage(Utf8BufferTextReader textReader, IInvocationBinder binder) { try { // We parse using the JsonTextReader directly but this has a problem. Some of our properties are dependent on other properties // and since reading the json might be unordered, we need to store the parsed content as JToken to re-parse when true types are known. // if we're lucky and the state we need to directly parse is available, then we'll use it. int? type = null; string invocationId = null; string target = null; string error = null; var hasItem = false; object item = null; JToken itemToken = null; var hasResult = false; object result = null; JToken resultToken = null; var hasArguments = false; object[] arguments = null; JArray argumentsToken = null; ExceptionDispatchInfo argumentBindingException = null; Dictionary <string, string> headers = null; var completed = false; using (var reader = JsonUtils.CreateJsonTextReader(textReader)) { reader.DateParseHandling = DateParseHandling.None; JsonUtils.CheckRead(reader); // We're always parsing a JSON object JsonUtils.EnsureObjectStart(reader); do { switch (reader.TokenType) { case JsonToken.PropertyName: var memberName = reader.Value.ToString(); switch (memberName) { case TypePropertyName: var messageType = JsonUtils.ReadAsInt32(reader, TypePropertyName); if (messageType == null) { throw new InvalidDataException($"Missing required property '{TypePropertyName}'."); } type = messageType.Value; break; case InvocationIdPropertyName: invocationId = JsonUtils.ReadAsString(reader, InvocationIdPropertyName); break; case TargetPropertyName: target = JsonUtils.ReadAsString(reader, TargetPropertyName); break; case ErrorPropertyName: error = JsonUtils.ReadAsString(reader, ErrorPropertyName); break; case ResultPropertyName: JsonUtils.CheckRead(reader); hasResult = true; if (string.IsNullOrEmpty(invocationId)) { // If we don't have an invocation id then we need to store it as a JToken so we can parse it later resultToken = JToken.Load(reader); } else { // If we have an invocation id already we can parse the end result var returnType = binder.GetReturnType(invocationId); result = PayloadSerializer.Deserialize(reader, returnType); } break; case ItemPropertyName: JsonUtils.CheckRead(reader); hasItem = true; if (string.IsNullOrEmpty(invocationId)) { // If we don't have an invocation id then we need to store it as a JToken so we can parse it later itemToken = JToken.Load(reader); } else { var returnType = binder.GetReturnType(invocationId); item = PayloadSerializer.Deserialize(reader, returnType); } break; case ArgumentsPropertyName: JsonUtils.CheckRead(reader); if (reader.TokenType != JsonToken.StartArray) { throw new InvalidDataException($"Expected '{ArgumentsPropertyName}' to be of type {JTokenType.Array}."); } hasArguments = true; if (string.IsNullOrEmpty(target)) { // We don't know the method name yet so just parse an array of generic JArray argumentsToken = JArray.Load(reader); } else { try { var paramTypes = binder.GetParameterTypes(target); arguments = BindArguments(reader, paramTypes); } catch (Exception ex) { argumentBindingException = ExceptionDispatchInfo.Capture(ex); } } break; case HeadersPropertyName: JsonUtils.CheckRead(reader); headers = ReadHeaders(reader); break; default: // Skip read the property name JsonUtils.CheckRead(reader); // Skip the value for this property reader.Skip(); break; } break; case JsonToken.EndObject: completed = true; break; } }while (!completed && JsonUtils.CheckRead(reader)); } HubMessage message; switch (type) { case HubProtocolConstants.InvocationMessageType: { if (argumentsToken != null) { try { var paramTypes = binder.GetParameterTypes(target); arguments = BindArguments(argumentsToken, paramTypes); } catch (Exception ex) { argumentBindingException = ExceptionDispatchInfo.Capture(ex); } } message = BindInvocationMessage(invocationId, target, argumentBindingException, arguments, hasArguments, binder); } break; case HubProtocolConstants.StreamInvocationMessageType: { if (argumentsToken != null) { try { var paramTypes = binder.GetParameterTypes(target); arguments = BindArguments(argumentsToken, paramTypes); } catch (Exception ex) { argumentBindingException = ExceptionDispatchInfo.Capture(ex); } } message = BindStreamInvocationMessage(invocationId, target, argumentBindingException, arguments, hasArguments, binder); } break; case HubProtocolConstants.StreamItemMessageType: if (itemToken != null) { var returnType = binder.GetReturnType(invocationId); item = itemToken.ToObject(returnType, PayloadSerializer); } message = BindStreamItemMessage(invocationId, item, hasItem, binder); break; case HubProtocolConstants.CompletionMessageType: if (resultToken != null) { var returnType = binder.GetReturnType(invocationId); result = resultToken.ToObject(returnType, PayloadSerializer); } message = BindCompletionMessage(invocationId, error, result, hasResult, binder); break; case HubProtocolConstants.CancelInvocationMessageType: message = BindCancelInvocationMessage(invocationId); break; case HubProtocolConstants.PingMessageType: return(PingMessage.Instance); case HubProtocolConstants.CloseMessageType: return(BindCloseMessage(error)); case null: throw new InvalidDataException($"Missing required property '{TypePropertyName}'."); default: // Future protocol changes can add message types, old clients can ignore them return(null); } return(ApplyHeaders(message, headers)); } catch (JsonReaderException jrex) { throw new InvalidDataException("Error reading JSON.", jrex); } }
private HubProtocol(ConnectionContext connection, int?maximumMessageSize, IHubProtocol hubProtocol, IInvocationBinder invocationBinder) { _connection = connection; _maximumMessageSize = maximumMessageSize; _hubProtocol = hubProtocol; _invocationBinder = invocationBinder; _runningTask = RunAsync(); }
public TestClient(bool synchronousCallbacks = false, IHubProtocol protocol = null, IInvocationBinder invocationBinder = null, bool addClaimId = false) { var options = new ChannelOptimizations { AllowSynchronousContinuations = synchronousCallbacks }; var transportToApplication = Channel.CreateUnbounded <byte[]>(options); var applicationToTransport = Channel.CreateUnbounded <byte[]>(options); Application = ChannelConnection.Create <byte[]>(input: applicationToTransport, output: transportToApplication); _transport = ChannelConnection.Create <byte[]>(input: transportToApplication, output: applicationToTransport); Connection = new DefaultConnectionContext(Guid.NewGuid().ToString(), _transport, Application); var claimValue = Interlocked.Increment(ref _id).ToString(); var claims = new List <Claim> { new Claim(ClaimTypes.Name, claimValue) }; if (addClaimId) { claims.Add(new Claim(ClaimTypes.NameIdentifier, claimValue)); } Connection.User = new ClaimsPrincipal(new ClaimsIdentity(claims)); Connection.Metadata["ConnectedTask"] = new TaskCompletionSource <bool>(); protocol = protocol ?? new JsonHubProtocol(); _protocolReaderWriter = new HubProtocolReaderWriter(protocol, new PassThroughEncoder()); _invocationBinder = invocationBinder ?? new DefaultInvocationBinder(); _cts = new CancellationTokenSource(); using (var memoryStream = new MemoryStream()) { NegotiationProtocol.WriteMessage(new NegotiationMessage(protocol.Name), memoryStream); Application.Out.TryWrite(memoryStream.ToArray()); } }