Ejemplo n.º 1
0
 private void InitializeHub(THub hub, HubConnectionContext connection)
 {
     hub.Clients = _hubContext.Clients;
     hub.Context = new HubCallerContext(connection);
     hub.Groups  = _hubContext.Groups;
 }
Ejemplo n.º 2
0
        public async Task OnConnectedAsync(ConnectionContext connection)
        {
            var output = Channel.CreateUnbounded <HubMessage>();

            // Set the hub feature before doing anything else. This stores
            // all the relevant state for a SignalR Hub connection.
            connection.Features.Set <IHubFeature>(new HubFeature());

            var connectionContext = new HubConnectionContext(output, connection);

            if (!await ProcessNegotiate(connectionContext))
            {
                return;
            }

            // Hubs support multiple producers so we set up this loop to copy
            // data written to the HubConnectionContext's channel to the transport channel
            var protocolReaderWriter = connectionContext.ProtocolReaderWriter;

            async Task WriteToTransport()
            {
                try
                {
                    while (await output.In.WaitToReadAsync())
                    {
                        while (output.In.TryRead(out var hubMessage))
                        {
                            var buffer = protocolReaderWriter.WriteMessage(hubMessage);
                            while (await connection.Transport.Out.WaitToWriteAsync())
                            {
                                if (connection.Transport.Out.TryWrite(buffer))
                                {
                                    break;
                                }
                            }
                        }
                    }
                }
                catch (Exception ex)
                {
                    connectionContext.Abort(ex);
                }
            }

            var writingOutputTask = WriteToTransport();

            try
            {
                await _lifetimeManager.OnConnectedAsync(connectionContext);
                await RunHubAsync(connectionContext);
            }
            finally
            {
                await _lifetimeManager.OnDisconnectedAsync(connectionContext);

                // Nothing should be writing to the HubConnectionContext
                output.Out.TryComplete();

                // This should unwind once we complete the output
                await writingOutputTask;
            }
        }
        private async Task DispatchMessagesAsync(HubConnectionContext connection)
        {
            var input    = connection.Input;
            var protocol = connection.Protocol;

            connection.BeginClientTimeout();


            var binder = new HubConnectionBinder <THub>(_dispatcher, connection);

            while (true)
            {
                var result = await input.ReadAsync();

                var buffer = result.Buffer;

                connection.ResetClientTimeout();

                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))
                            {
                                messageReceived = true;
                                connection.StopClientTimeout();
                                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))
                                {
                                    messageReceived = true;
                                    connection.StopClientTimeout();

                                    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();
                            }
                        }
                    }
Ejemplo n.º 4
0
        private async Task Invoke(HubMethodDescriptor descriptor, HubConnectionContext connection, InvocationMessage invocationMessage)
        {
            var methodExecutor = descriptor.MethodExecutor;

            using (var scope = _serviceScopeFactory.CreateScope())
            {
                if (!await IsHubMethodAuthorized(scope.ServiceProvider, connection.User, descriptor.Policies))
                {
                    _logger.HubMethodNotAuthorized(invocationMessage.Target);
                    if (!invocationMessage.NonBlocking)
                    {
                        await SendMessageAsync(connection, CompletionMessage.WithError(invocationMessage.InvocationId, $"Failed to invoke '{invocationMessage.Target}' because user is unauthorized"));
                    }
                    return;
                }

                var hubActivator = scope.ServiceProvider.GetRequiredService <IHubActivator <THub> >();
                var hub          = hubActivator.Create();

                try
                {
                    InitializeHub(hub, connection);

                    object result = null;

                    // ReadableChannel is awaitable but we don't want to await it.
                    if (methodExecutor.IsMethodAsync && !IsChannel(methodExecutor.MethodReturnType, out _))
                    {
                        if (methodExecutor.MethodReturnType == typeof(Task))
                        {
                            await(Task) methodExecutor.Execute(hub, invocationMessage.Arguments);
                        }
                        else
                        {
                            result = await methodExecutor.ExecuteAsync(hub, invocationMessage.Arguments);
                        }
                    }
                    else
                    {
                        result = methodExecutor.Execute(hub, invocationMessage.Arguments);
                    }

                    if (IsStreamed(connection, methodExecutor, result, methodExecutor.MethodReturnType, out var enumerator))
                    {
                        _logger.StreamingResult(invocationMessage.InvocationId, methodExecutor.MethodReturnType.FullName);
                        await StreamResultsAsync(invocationMessage.InvocationId, connection, enumerator);
                    }
                    else if (!invocationMessage.NonBlocking)
                    {
                        _logger.SendingResult(invocationMessage.InvocationId, methodExecutor.MethodReturnType.FullName);
                        await SendMessageAsync(connection, CompletionMessage.WithResult(invocationMessage.InvocationId, result));
                    }
                }
                catch (TargetInvocationException ex)
                {
                    _logger.FailedInvokingHubMethod(invocationMessage.Target, ex);
                    if (!invocationMessage.NonBlocking)
                    {
                        await SendMessageAsync(connection, CompletionMessage.WithError(invocationMessage.InvocationId, ex.InnerException.Message));
                    }
                }
                catch (Exception ex)
                {
                    _logger.FailedInvokingHubMethod(invocationMessage.Target, ex);
                    if (!invocationMessage.NonBlocking)
                    {
                        await SendMessageAsync(connection, CompletionMessage.WithError(invocationMessage.InvocationId, ex.Message));
                    }
                }
                finally
                {
                    hubActivator.Release(hub);
                }
            }
        }
 public override Task OnConnectedAsync(HubConnectionContext connection)
 {
     _connections.Add(connection);
     return(Task.CompletedTask);
 }
Ejemplo n.º 6
0
 public static void AddUid(this HubConnectionContext connection, string uid)
 {
     connection.Metadata.Add("UID", uid);
 }
Ejemplo n.º 7
0
 private Task SendMessageAsync(HubConnectionContext connection, HubMessage hubMessage)
 {
     return(connection.WriteAsync(hubMessage));
 }
Ejemplo n.º 8
0
 public void Remove(HubConnectionContext connection)
 {
     _connections.TryRemove(connection.ConnectionId, out _);
 }
 protected Hub()
 {
     Clients = new HubConnectionContext();
 }
Ejemplo n.º 10
0
        private async Task DispatchMessagesAsync(HubConnectionContext connection)
        {
            // Since we dispatch multiple hub invocations in parallel, we need a way to communicate failure back to the main processing loop.
            // This is done by aborting the connection.

            try
            {
                while (true)
                {
                    var result = await connection.Input.ReadAsync(connection.ConnectionAbortedToken);

                    var buffer   = result.Buffer;
                    var consumed = buffer.End;
                    var examined = buffer.End;

                    try
                    {
                        if (!buffer.IsEmpty)
                        {
                            if (connection.ProtocolReaderWriter.ReadMessages(buffer, this, out var hubMessages, out consumed, out examined))
                            {
                                foreach (var hubMessage in hubMessages)
                                {
                                    switch (hubMessage)
                                    {
                                    case InvocationMessage invocationMessage:
                                        _logger.ReceivedHubInvocation(invocationMessage);

                                        // Don't wait on the result of execution, continue processing other
                                        // incoming messages on this connection.
                                        _ = ProcessInvocation(connection, invocationMessage, isStreamedInvocation: false);
                                        break;

                                    case StreamInvocationMessage streamInvocationMessage:
                                        _logger.ReceivedStreamHubInvocation(streamInvocationMessage);

                                        // Don't wait on the result of execution, continue processing other
                                        // incoming messages on this connection.
                                        _ = ProcessInvocation(connection, streamInvocationMessage, isStreamedInvocation: true);
                                        break;

                                    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))
                                        {
                                            _logger.CancelStream(cancelInvocationMessage.InvocationId);
                                            cts.Cancel();
                                        }
                                        else
                                        {
                                            // Stream can be canceled on the server while client is canceling stream.
                                            _logger.UnexpectedCancel();
                                        }
                                        break;

                                    case PingMessage _:
                                        // We don't care about pings
                                        break;

                                    // Other kind of message we weren't expecting
                                    default:
                                        _logger.UnsupportedMessageReceived(hubMessage.GetType().FullName);
                                        throw new NotSupportedException($"Received unsupported message: {hubMessage}");
                                    }
                                }
                            }
                        }
                        else if (result.IsCompleted)
                        {
                            break;
                        }
                    }
                    finally
                    {
                        connection.Input.AdvanceTo(consumed, examined);
                    }
                }
            }
            catch (OperationCanceledException)
            {
                // If there's an exception, bubble it to the caller
                connection.AbortException?.Throw();
            }
        }
Ejemplo n.º 11
0
 public async Task OnCompletionAsync(HubConnectionContext connection, CompletionMessage message)
 {
     var hubName = GetHubName(connection);
     await _hubMessageBroker.PassThruServerMessage(hubName, connection, message);
 }
Ejemplo n.º 12
0
 public HubCallerContext(HubConnectionContext connection)
 {
     Connection = connection;
 }
Ejemplo n.º 13
0
 public static string GetHubName(this HubConnectionContext connection)
 {
     return(connection.GetHttpContext()?.Request.Query["hub"]);
 }
Ejemplo n.º 14
0
 public async Task OnCompletionAsync(HubConnectionContext connection, CompletionMessage message)
 {
     await Task.CompletedTask;
 }
Ejemplo n.º 15
0
        private async Task <bool> ValidateInvocationMode(Type resultType, bool isStreamedInvocation,
                                                         HubMethodInvocationMessage hubMethodInvocationMessage, HubConnectionContext connection)
        {
            var isStreamedResult = IsStreamed(resultType);

            if (isStreamedResult && !isStreamedInvocation)
            {
                // Non-null/empty InvocationId? Blocking
                if (!string.IsNullOrEmpty(hubMethodInvocationMessage.InvocationId))
                {
                    _logger.StreamingMethodCalledWithInvoke(hubMethodInvocationMessage);
                    await SendMessageAsync(connection, CompletionMessage.WithError(hubMethodInvocationMessage.InvocationId,
                                                                                   $"The client attempted to invoke the streaming '{hubMethodInvocationMessage.Target}' method in a non-streaming fashion."));
                }

                return(false);
            }

            if (!isStreamedResult && isStreamedInvocation)
            {
                _logger.NonStreamingMethodCalledWithStream(hubMethodInvocationMessage);
                await SendMessageAsync(connection, CompletionMessage.WithError(hubMethodInvocationMessage.InvocationId,
                                                                               $"The client attempted to invoke the non-streaming '{hubMethodInvocationMessage.Target}' method in a streaming fashion."));

                return(false);
            }

            return(true);
        }
Ejemplo n.º 16
0
 public void Add(HubConnectionContext connection)
 {
     _connections.TryAdd(connection.ConnectionId, connection);
 }
Ejemplo n.º 17
0
 public static HttpContext GetHttpContext(this HubConnectionContext connection)
 {
     return(connection.Features.Get <IHttpContextFeature>()?.HttpContext);
 }
Ejemplo n.º 18
0
 /// <inheritdoc />
 public virtual string? GetUserId(HubConnectionContext connection)
 {
     return connection.User.FindFirst(ClaimTypes.NameIdentifier)?.Value;
 }
Ejemplo n.º 19
0
 public abstract Task OnDisconnectedAsync(HubConnectionContext connection);
 public override Task OnDisconnectedAsync(HubConnectionContext connection)
 {
     _connections.Remove(connection);
     _groups.RemoveDisconnectedConnection(connection.ConnectionId);
     return(Task.CompletedTask);
 }
Ejemplo n.º 21
0
 public static void AddRouteTarget(this HubConnectionContext connection, RouteTarget target)
 {
     connection.Metadata.Add("Target", target);
 }