private async Task <bool> ValidateInvocationMode(HubMethodDescriptor hubMethodDescriptor, bool isStreamResponse, HubMethodInvocationMessage hubMethodInvocationMessage, HubConnectionContext connection) { if (hubMethodDescriptor.IsStreamResponse && !isStreamResponse) { // Non-null/empty InvocationId? Blocking if (!string.IsNullOrEmpty(hubMethodInvocationMessage.InvocationId)) { Log.StreamingMethodCalledWithInvoke(_logger, hubMethodInvocationMessage); await connection.WriteAsync(CompletionMessage.WithError(hubMethodInvocationMessage.InvocationId, $"The client attempted to invoke the streaming '{hubMethodInvocationMessage.Target}' method with a non-streaming invocation.")); } return(false); } if (!hubMethodDescriptor.IsStreamResponse && isStreamResponse) { Log.NonStreamingMethodCalledWithStream(_logger, hubMethodInvocationMessage); await connection.WriteAsync(CompletionMessage.WithError(hubMethodInvocationMessage.InvocationId, $"The client attempted to invoke the non-streaming '{hubMethodInvocationMessage.Target}' method with a streaming invocation.")); return(false); } return(true); }
private async Task Invoke(HubMethodDescriptor descriptor, HubConnectionContext connection, HubMethodInvocationMessage hubMethodInvocationMessage, bool isStreamResponse, bool isStreamCall) { var methodExecutor = descriptor.MethodExecutor; var disposeScope = true; var scope = _serviceScopeFactory.CreateScope(); IHubActivator <THub> hubActivator = null; THub hub = null; try { if (!await IsHubMethodAuthorized(scope.ServiceProvider, connection, descriptor.Policies, descriptor.MethodExecutor.MethodInfo.Name, hubMethodInvocationMessage.Arguments)) { Log.HubMethodNotAuthorized(_logger, hubMethodInvocationMessage.Target); await SendInvocationError(hubMethodInvocationMessage.InvocationId, connection, $"Failed to invoke '{hubMethodInvocationMessage.Target}' because user is unauthorized"); return; } if (!await ValidateInvocationMode(descriptor, isStreamResponse, hubMethodInvocationMessage, connection)) { return; } hubActivator = scope.ServiceProvider.GetRequiredService <IHubActivator <THub> >(); hub = hubActivator.Create(); try { var clientStreamLength = hubMethodInvocationMessage.StreamIds?.Length ?? 0; var serverStreamLength = descriptor.StreamingParameters?.Count ?? 0; if (clientStreamLength != serverStreamLength) { var ex = new HubException($"Client sent {clientStreamLength} stream(s), Hub method expects {serverStreamLength}."); Log.InvalidHubParameters(_logger, hubMethodInvocationMessage.Target, ex); await SendInvocationError(hubMethodInvocationMessage.InvocationId, connection, ErrorMessageHelper.BuildErrorMessage($"An unexpected error occurred invoking '{hubMethodInvocationMessage.Target}' on the server.", ex, _enableDetailedErrors)); return; } InitializeHub(hub, connection); Task invocation = null; CancellationTokenSource cts = null; var arguments = hubMethodInvocationMessage.Arguments; if (descriptor.HasSyntheticArguments) { // In order to add the synthetic arguments we need a new array because the invocation array is too small (it doesn't know about synthetic arguments) arguments = new object[descriptor.OriginalParameterTypes.Count]; var streamPointer = 0; var hubInvocationArgumentPointer = 0; for (var parameterPointer = 0; parameterPointer < arguments.Length; parameterPointer++) { if (hubMethodInvocationMessage.Arguments.Length > hubInvocationArgumentPointer && (hubMethodInvocationMessage.Arguments[hubInvocationArgumentPointer] == null || descriptor.OriginalParameterTypes[parameterPointer].IsAssignableFrom(hubMethodInvocationMessage.Arguments[hubInvocationArgumentPointer].GetType()))) { // The types match so it isn't a synthetic argument, just copy it into the arguments array arguments[parameterPointer] = hubMethodInvocationMessage.Arguments[hubInvocationArgumentPointer]; hubInvocationArgumentPointer++; } else { if (descriptor.OriginalParameterTypes[parameterPointer] == typeof(CancellationToken)) { cts = CancellationTokenSource.CreateLinkedTokenSource(connection.ConnectionAborted); arguments[parameterPointer] = cts.Token; } else if (isStreamCall && ReflectionHelper.IsStreamingType(descriptor.OriginalParameterTypes[parameterPointer], mustBeDirectType: true)) { Log.StartingParameterStream(_logger, hubMethodInvocationMessage.StreamIds[streamPointer]); var itemType = descriptor.StreamingParameters[streamPointer]; arguments[parameterPointer] = connection.StreamTracker.AddStream(hubMethodInvocationMessage.StreamIds[streamPointer], itemType, descriptor.OriginalParameterTypes[parameterPointer]); streamPointer++; } else { // This should never happen Debug.Assert(false, $"Failed to bind argument of type '{descriptor.OriginalParameterTypes[parameterPointer].Name}' for hub method '{methodExecutor.MethodInfo.Name}'."); } } } } if (isStreamResponse) { var result = await ExecuteHubMethod(methodExecutor, hub, arguments); if (result == null) { Log.InvalidReturnValueFromStreamingMethod(_logger, methodExecutor.MethodInfo.Name); await SendInvocationError(hubMethodInvocationMessage.InvocationId, connection, $"The value returned by the streaming method '{methodExecutor.MethodInfo.Name}' is not a ChannelReader<> or IAsyncEnumerable<>."); return; } cts = cts ?? CancellationTokenSource.CreateLinkedTokenSource(connection.ConnectionAborted); connection.ActiveRequestCancellationSources.TryAdd(hubMethodInvocationMessage.InvocationId, cts); var enumerable = descriptor.FromReturnedStream(result, cts.Token); Log.StreamingResult(_logger, hubMethodInvocationMessage.InvocationId, methodExecutor); _ = StreamResultsAsync(hubMethodInvocationMessage.InvocationId, connection, enumerable, scope, hubActivator, hub, cts, hubMethodInvocationMessage); } else { // Invoke or Send async Task ExecuteInvocation() { object result; try { result = await ExecuteHubMethod(methodExecutor, hub, arguments); Log.SendingResult(_logger, hubMethodInvocationMessage.InvocationId, methodExecutor); } catch (Exception ex) { Log.FailedInvokingHubMethod(_logger, hubMethodInvocationMessage.Target, ex); await SendInvocationError(hubMethodInvocationMessage.InvocationId, connection, ErrorMessageHelper.BuildErrorMessage($"An unexpected error occurred invoking '{hubMethodInvocationMessage.Target}' on the server.", ex, _enableDetailedErrors)); return; } finally { // Stream response handles cleanup in StreamResultsAsync // And normal invocations handle cleanup below in the finally if (isStreamCall) { await CleanupInvocation(connection, hubMethodInvocationMessage, hubActivator, hub, scope); } } // No InvocationId - Send Async, no response expected if (!string.IsNullOrEmpty(hubMethodInvocationMessage.InvocationId)) { // Invoke Async, one reponse expected await connection.WriteAsync(CompletionMessage.WithResult(hubMethodInvocationMessage.InvocationId, result)); } } invocation = ExecuteInvocation(); } if (isStreamCall || isStreamResponse) { // don't await streaming invocations // leave them running in the background, allowing dispatcher to process other messages between streaming items disposeScope = false; } else { // complete the non-streaming calls now await invocation; } } catch (TargetInvocationException ex) { Log.FailedInvokingHubMethod(_logger, hubMethodInvocationMessage.Target, ex); await SendInvocationError(hubMethodInvocationMessage.InvocationId, connection, ErrorMessageHelper.BuildErrorMessage($"An unexpected error occurred invoking '{hubMethodInvocationMessage.Target}' on the server.", ex.InnerException, _enableDetailedErrors)); } catch (Exception ex) { Log.FailedInvokingHubMethod(_logger, hubMethodInvocationMessage.Target, ex); await SendInvocationError(hubMethodInvocationMessage.InvocationId, connection, ErrorMessageHelper.BuildErrorMessage($"An unexpected error occurred invoking '{hubMethodInvocationMessage.Target}' on the server.", ex, _enableDetailedErrors)); } } finally { if (disposeScope) { await CleanupInvocation(connection, hubMethodInvocationMessage, hubActivator, hub, scope); } } }
public string GetUserId(HubConnectionContext connection) { return(connection.User?.Identity?.Name); }
protected Hub() { Clients = new HubConnectionContext(); }
public Task UpdateUser(HubConnectionContext connection, UserDetailsDto userDetails) { _usersOnline.AddOrUpdate(connection, userDetails, (oldKey, oldValue) => userDetails); return(Task.CompletedTask); }
public override Task OnDisconnectedAsync(HubConnectionContext connection) { return(Task.CompletedTask); }
private async Task DispatchMessagesAsync(HubConnectionContext connection) { var input = connection.Input; var protocol = connection.Protocol; connection.BeginClientTimeout(); var binder = new HubConnectionBinder <THub>(_dispatcher, _lifetimeManager, connection); while (true) { var result = await input.ReadAsync(); var buffer = result.Buffer; try { if (result.IsCanceled) { break; } if (!buffer.IsEmpty) { bool messageReceived = false; // No message limit, just parse and dispatch if (_maximumMessageSize == null) { while (protocol.TryParseMessage(ref buffer, binder, out var message)) { connection.StopClientTimeout(); // This lets us know the timeout has stopped and we need to re-enable it after dispatching the message messageReceived = true; await _dispatcher.DispatchMessageAsync(connection, message); } if (messageReceived) { connection.BeginClientTimeout(); } } else { // We give the parser a sliding window of the default message size var maxMessageSize = _maximumMessageSize.Value; while (!buffer.IsEmpty) { var segment = buffer; var overLength = false; if (segment.Length > maxMessageSize) { segment = segment.Slice(segment.Start, maxMessageSize); overLength = true; } if (protocol.TryParseMessage(ref segment, binder, out var message)) { connection.StopClientTimeout(); // This lets us know the timeout has stopped and we need to re-enable it after dispatching the message messageReceived = true; await _dispatcher.DispatchMessageAsync(connection, message); } else if (overLength) { throw new InvalidDataException($"The maximum message size of {maxMessageSize}B was exceeded. The message size can be configured in AddHubOptions."); } else { // No need to update the buffer since we didn't parse anything break; } // Update the buffer to the remaining segment buffer = buffer.Slice(segment.Start); } if (messageReceived) { connection.BeginClientTimeout(); } } }
public override Task OnDisconnectedAsync(HubConnectionContext connection) { throw new NotSupportedException(); }
/// <summary> /// Returns the User ID for the given <see cref="HubConnectionContext"/>. /// </summary> /// <param name="connection">The <see cref="HubConnectionContext"/> of the user to locate.</param> /// <returns>The value of the <see cref="UserIdClaimName"/> claim.</returns> public virtual string GetUserId(HubConnectionContext connection) => GetUserId(connection.User);
public string GetUserId(HubConnectionContext connection) { return(connection.User?.Claims? .Where(x => x.Type == nameof(User.Id)) .Select(x => x.Value).FirstOrDefault()); }
public override Task OnDisconnectedAsync(HubConnectionContext connection) { throw new System.NotImplementedException(); }
public string GetUserId(HubConnectionContext connection) { throw new System.NotImplementedException(); }
public string GetUserId(HubConnectionContext connection) { return("UserId!"); }
public virtual string GetUserId(HubConnectionContext connection) => connection.User?.FindFirst(ClaimTypes.Name)?.Value;
private Task SendLocal(HubConnectionContext connection, HubInvocationMessage hubMessage) { _logger.LogDebug("Sending local message to connection {connectionId} on hub {hubName} (serverId: {serverId})", connection.ConnectionId, _hubName, _serverId); return(connection.WriteAsync(hubMessage).AsTask()); }
public string GetUserId(HubConnectionContext connection) { return(connection.User?.FindFirst("sub")?.Value); }
public string GetUserId(HubConnectionContext connection) => connection.GetHttpContext().Request.Query["token"];
public Task <UserDetailsDto> GetUser(HubConnectionContext connection) { var user = _usersOnline.Values.FirstOrDefault(u => u.ConnectionId == connection.ConnectionId); return(Task.FromResult(user)); }
public virtual string GetUserId(HubConnectionContext connection) { return(connection.User?.Claims.FirstOrDefault(x => x.Value != null).Value); }
/// <summary> /// GetUserId /// </summary> /// <param name="connection"></param> /// <returns></returns> public string GetUserId(HubConnectionContext connection) { return(connection.User?.FindFirst(ClaimTypes.Name)?.Value); }
public string?GetUserId(HubConnectionContext connection) { return(connection.User.GetClaim("id")?.Value); }
string IUserIdProvider.GetUserId(HubConnectionContext connection) { return(connection.User?.Claims?.FirstOrDefault(c => c.Type == JwtCustomClaimNames.Id)?.Value); }
public virtual string GetUserId(HubConnectionContext connection) { return(connection.User?.FindFirst(ClaimTypes.NameIdentifier)?.Value); }
private Task ProcessStreamItem(HubConnectionContext connection, StreamItemMessage message) { Log.ReceivedStreamItem(_logger, message); return(connection.StreamTracker.ProcessItem(message)); }
public virtual string GetUserId(HubConnectionContext connection) { return(connection.User.FindFirstValue(AppConstants.SubjectClaimName)); }
private void InitializeHub(THub hub, HubConnectionContext connection) { hub.Clients = new HubCallerClients(_hubContext.Clients, connection.ConnectionId); hub.Context = connection.HubCallerContext; hub.Groups = _hubContext.Groups; }
public string GetUserId(HubConnectionContext connection) { return(connection.User?.FindFirst(claim => claim.Type == "username")?.Value); }
public override Task DispatchMessageAsync(HubConnectionContext connection, HubMessage hubMessage) { // Messages are dispatched sequentially and will stop other messages from being processed until they complete. // Streaming methods will run sequentially until they start streaming, then they will fire-and-forget allowing other messages to run. switch (hubMessage) { case InvocationBindingFailureMessage bindingFailureMessage: return(ProcessInvocationBindingFailure(connection, bindingFailureMessage)); case StreamBindingFailureMessage bindingFailureMessage: return(ProcessStreamBindingFailure(connection, bindingFailureMessage)); case InvocationMessage invocationMessage: Log.ReceivedHubInvocation(_logger, invocationMessage); return(ProcessInvocation(connection, invocationMessage, isStreamResponse: false)); case StreamInvocationMessage streamInvocationMessage: Log.ReceivedStreamHubInvocation(_logger, streamInvocationMessage); return(ProcessInvocation(connection, streamInvocationMessage, isStreamResponse: true)); case CancelInvocationMessage cancelInvocationMessage: // Check if there is an associated active stream and cancel it if it exists. // The cts will be removed when the streaming method completes executing if (connection.ActiveRequestCancellationSources.TryGetValue(cancelInvocationMessage.InvocationId, out var cts)) { Log.CancelStream(_logger, cancelInvocationMessage.InvocationId); cts.Cancel(); } else { // Stream can be canceled on the server while client is canceling stream. Log.UnexpectedCancel(_logger); } break; case PingMessage _: connection.StartClientTimeout(); break; case StreamItemMessage streamItem: return(ProcessStreamItem(connection, streamItem)); case CompletionMessage streamCompleteMessage: // closes channels, removes from Lookup dict // user's method can see the channel is complete and begin wrapping up if (connection.StreamTracker.TryComplete(streamCompleteMessage)) { Log.CompletingStream(_logger, streamCompleteMessage); } else { Log.UnexpectedStreamCompletion(_logger); } break; // Other kind of message we weren't expecting default: Log.UnsupportedMessageReceived(_logger, hubMessage.GetType().FullName); throw new NotSupportedException($"Received unsupported message: {hubMessage}"); } return(Task.CompletedTask); }
public string GetUserId(HubConnectionContext hubConnection) { string userId = "dummyUser"; return(userId); }
public string GetUserId(HubConnectionContext connection) => connection.User?.FindFirstValue("sub");