コード例 #1
0
        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);
        }
コード例 #2
0
 private async Task ProcessInvocation(HubConnectionContext connection,
                                      HubMethodInvocationMessage hubMethodInvocationMessage, bool isStreamedInvocation)
 {
     try
     {
         // If an unexpected exception occurs then we want to kill the entire connection
         // by ending the processing loop
         if (!_methods.TryGetValue(hubMethodInvocationMessage.Target, out var descriptor))
         {
             // Send an error to the client. Then let the normal completion process occur
             Log.UnknownHubMethod(_logger, hubMethodInvocationMessage.Target);
             await connection.WriteAsync(CompletionMessage.WithError(
                                             hubMethodInvocationMessage.InvocationId, $"Unknown hub method '{hubMethodInvocationMessage.Target}'"));
         }
         else
         {
             await Invoke(descriptor, connection, hubMethodInvocationMessage, isStreamedInvocation);
         }
     }
     catch (Exception ex)
     {
         // Abort the entire connection if the invocation fails in an unexpected way
         connection.Abort(ex);
     }
 }
        public async Task GetMessages_LastMessageId_InvocationMessageIsSent()
        {
            var sessionId = Guid.NewGuid();

            await using var fixture = new PlanningPokerSignalRClientFixture();

            var resultTask = fixture.Target.GetMessages(PlanningPokerData.TeamName, PlanningPokerData.MemberName, sessionId, 2157483849, fixture.CancellationToken);

            var sentMessage = await fixture.GetSentMessage();

            Assert.IsNotNull(sentMessage);
            Assert.IsInstanceOfType(sentMessage, typeof(InvocationMessage));
            var sentInvocationMessage = (InvocationMessage)sentMessage;

            Assert.AreEqual(RequestName, sentInvocationMessage.Target);
            var expectedArguments = new object[] { PlanningPokerData.TeamName, PlanningPokerData.MemberName, sessionId, 2157483849L };

            CollectionAssert.AreEqual(expectedArguments, sentInvocationMessage.Arguments);

            var notifyMessage = new InvocationMessage(ResponseName, new object[] { new List <Message>() });
            await fixture.ReceiveMessage(notifyMessage);

            var returnMessage = new CompletionMessage(sentInvocationMessage.InvocationId, null, null, false);
            await fixture.ReceiveMessage(returnMessage);

            await resultTask;

            // Ensure asynchronous Dispose. Otherwise, Dispose is executed in OnNotify handler and it causes deadlock.
            await Task.Yield();
        }
コード例 #4
0
        private async Task Invoke(HubMethodDescriptor descriptor, HubConnectionContext connection,
                                  HubMethodInvocationMessage hubMethodInvocationMessage, bool isStreamedInvocation)
        {
            var methodExecutor = descriptor.MethodExecutor;

            using (var scope = _serviceScopeFactory.CreateScope())
            {
                if (!await IsHubMethodAuthorized(scope.ServiceProvider, connection.User, descriptor.Policies))
                {
                    _logger.HubMethodNotAuthorized(hubMethodInvocationMessage.Target);
                    await SendInvocationError(hubMethodInvocationMessage, connection,
                                              $"Failed to invoke '{hubMethodInvocationMessage.Target}' because user is unauthorized");

                    return;
                }

                if (!await ValidateInvocationMode(methodExecutor.MethodReturnType, isStreamedInvocation, hubMethodInvocationMessage, connection))
                {
                    return;
                }

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

                try
                {
                    InitializeHub(hub, connection);

                    var result = await ExecuteHubMethod(methodExecutor, hub, hubMethodInvocationMessage.Arguments);

                    if (isStreamedInvocation)
                    {
                        var enumerator = GetStreamingEnumerator(connection, hubMethodInvocationMessage.InvocationId, methodExecutor, result, methodExecutor.MethodReturnType);
                        _logger.StreamingResult(hubMethodInvocationMessage.InvocationId, methodExecutor.MethodReturnType.FullName);
                        await StreamResultsAsync(hubMethodInvocationMessage.InvocationId, connection, enumerator);
                    }
                    // Non-empty/null InvocationId ==> Blocking invocation that needs a response
                    else if (!string.IsNullOrEmpty(hubMethodInvocationMessage.InvocationId))
                    {
                        _logger.SendingResult(hubMethodInvocationMessage.InvocationId, methodExecutor.MethodReturnType.FullName);
                        await SendMessageAsync(connection, CompletionMessage.WithResult(hubMethodInvocationMessage.InvocationId, result));
                    }
                }
                catch (TargetInvocationException ex)
                {
                    _logger.FailedInvokingHubMethod(hubMethodInvocationMessage.Target, ex);
                    await SendInvocationError(hubMethodInvocationMessage, connection, ex.InnerException.Message);
                }
                catch (Exception ex)
                {
                    _logger.FailedInvokingHubMethod(hubMethodInvocationMessage.Target, ex);
                    await SendInvocationError(hubMethodInvocationMessage, connection, ex.Message);
                }
                finally
                {
                    hubActivator.Release(hub);
                }
            }
        }
コード例 #5
0
 private bool CompletionMessagesEqual(CompletionMessage x, CompletionMessage y)
 {
     return(SequenceEqual(x.Headers, y.Headers) &&
            string.Equals(x.InvocationId, y.InvocationId, StringComparison.Ordinal) &&
            string.Equals(x.Error, y.Error, StringComparison.Ordinal) &&
            x.HasResult == y.HasResult &&
            (Equals(x.Result, y.Result) || SequenceEqual(x.Result, y.Result)));
 }
コード例 #6
0
        public void SerializerCanSerializeTypesWithNoDefaultCtor()
        {
            var result = Write(CompletionMessage.WithResult("0", new List <int> {
                42
            }.AsReadOnly()));

            AssertMessages(new byte[] { ArrayBytes(5), 3, 0x80, StringBytes(1), (byte)'0', 0x03, ArrayBytes(1), 42 }, result);
        }
コード例 #7
0
ファイル: StreamTracker.cs プロジェクト: jnm2/AspNetCore
 public void Complete(CompletionMessage message)
 {
     _lookup.TryRemove(message.InvocationId, out var converter);
     if (converter == null)
     {
         throw new KeyNotFoundException($"No stream with id '{message.InvocationId}' could be found.");
     }
     converter.TryComplete(message.HasResult || message.Error == null ? null : new Exception(message.Error));
 }
コード例 #8
0
        private async Task SendInvocationError(string invocationId,
                                               HubConnectionContext connection, string errorMessage)
        {
            if (string.IsNullOrEmpty(invocationId))
            {
                return;
            }

            await connection.WriteAsync(CompletionMessage.WithError(invocationId, errorMessage));
        }
コード例 #9
0
        private async Task SendInvocationError(HubMethodInvocationMessage hubMethodInvocationMessage,
                                               HubConnectionContext connection, string errorMessage)
        {
            if (string.IsNullOrEmpty(hubMethodInvocationMessage.InvocationId))
            {
                return;
            }

            await SendMessageAsync(connection, CompletionMessage.WithError(hubMethodInvocationMessage.InvocationId, errorMessage));
        }
コード例 #10
0
 public bool TryComplete(CompletionMessage message)
 {
     _lookup.TryRemove(message.InvocationId !, out var converter);
     if (converter == null)
     {
         return(false);
     }
     converter.TryComplete(message.HasResult || message.Error == null ? null : new Exception(message.Error));
     return(true);
 }
コード例 #11
0
        public override async Task <HttpResponseMessage> ExecuteAsync(HttpRequestMessage request)
        {
            if (!Resolver.TryGetInvocationContext(request, out var context))
            {
                //TODO: More detailed exception
                throw new SignalRTriggerException();
            }
            var(message, protocol) = await Resolver.GetMessageAsync <InvocationMessage>(request).ConfigureAwait(false);

            AssertConsistency(context, message);
            context.Arguments = message.Arguments;

            // Only when it's an invoke, we need the result from function execution.
            TaskCompletionSource <object> tcs = null;

            if (!string.IsNullOrEmpty(message.InvocationId))
            {
                tcs = new TaskCompletionSource <object>(TaskCreationOptions.RunContinuationsAsynchronously);
            }

            HttpResponseMessage response;
            CompletionMessage   completionMessage = null;

            var functionResult = await ExecuteWithAuthAsync(request, ExecutionContext, context, tcs).ConfigureAwait(false);

            if (tcs != null)
            {
                if (!functionResult.Succeeded)
                {
                    var errorMessage = functionResult.Exception?.InnerException?.Message ??
                                       functionResult.Exception?.Message ??
                                       "Method execution failed.";
                    completionMessage = CompletionMessage.WithError(message.InvocationId, errorMessage);
                    response          = new HttpResponseMessage(HttpStatusCode.OK);
                }
                else
                {
                    var result = await tcs.Task.ConfigureAwait(false);

                    completionMessage = CompletionMessage.WithResult(message.InvocationId, result);
                    response          = new HttpResponseMessage(HttpStatusCode.OK);
                }
            }
            else
            {
                response = new HttpResponseMessage(HttpStatusCode.OK);
            }

            if (completionMessage != null)
            {
                response.Content = new ByteArrayContent(protocol.GetMessageBytes(completionMessage).ToArray());
            }
            return(response);
        }
コード例 #12
0
            public override void Complete(CompletionMessage completionMessage)
            {
                if (!string.IsNullOrEmpty(completionMessage.Error))
                {
                    Fail(new HubException(completionMessage.Error));
                    return;
                }

                Log.InvocationCompleted(Logger, InvocationId);
                _completionSource.TrySetResult(completionMessage.Result);
            }
コード例 #13
0
        private async Task OnConnectedAsync(HubInvocationMessage message)
        {
            var connection = CreateHubConnectionContext(message);

            _connections.Add(connection);

            await _lifetimeManager.OnConnectedAsync(connection);

            await _hubInvoker.OnConnectedAsync(connection);

            await SendMessageAsync(CompletionMessage.WithResult(message.InvocationId, ""));
        }
コード例 #14
0
        public void CanWriteObjectsWithoutDefaultCtors()
        {
            var expectedPayload = new byte[] { 0x07, 0x94, 0x03, 0xa1, 0x30, 0x03, 0x91, 0x2a };

            using (var memoryStream = new MemoryStream())
            {
                _hubProtocol.WriteMessage(CompletionMessage.WithResult("0", new List <int> {
                    42
                }.AsReadOnly()), memoryStream);
                Assert.Equal(expectedPayload, memoryStream.ToArray());
            }
        }
コード例 #15
0
        private Task ProcessStreamBindingFailure(HubConnectionContext connection, StreamBindingFailureMessage bindingFailureMessage)
        {
            var errorString = ErrorMessageHelper.BuildErrorMessage(
                "Failed to bind Stream message.",
                bindingFailureMessage.BindingFailure.SourceException, _enableDetailedErrors);

            var message = CompletionMessage.WithError(bindingFailureMessage.Id, errorString);

            Log.ClosingStreamWithBindingError(_logger, message);
            connection.StreamTracker.Complete(message);

            return(Task.CompletedTask);
        }
コード例 #16
0
        private async Task OnCompletionAsync(CompletionMessage message)
        {
            var connection = GetHubConnectionContext(message);

            if (connection == null)
            {
                await SendMessageAsync(CompletionMessage.WithError(message.InvocationId, "No connection found."));

                return;
            }

            await _hubInvoker.OnCompletionAsync(connection, message);
        }
コード例 #17
0
ファイル: HubEndPoint.cs プロジェクト: YipingRuan/SignalR
 private async Task Execute(HubConnectionContext connection, InvocationMessage invocationMessage)
 {
     if (!_methods.TryGetValue(invocationMessage.Target, out var descriptor))
     {
         // Send an error to the client. Then let the normal completion process occur
         _logger.UnknownHubMethod(invocationMessage.Target);
         await SendMessageAsync(connection, CompletionMessage.WithError(invocationMessage.InvocationId, $"Unknown hub method '{invocationMessage.Target}'"));
     }
     else
     {
         await Invoke(descriptor, connection, invocationMessage);
     }
 }
コード例 #18
0
        private void DispatchInvocationCompletion(CompletionMessage completion, InvocationRequest irq)
        {
            _logger.ReceivedInvocationCompletion(completion.InvocationId);

            if (irq.CancellationToken.IsCancellationRequested)
            {
                _logger.CancelingInvocationCompletion(irq.InvocationId);
            }
            else
            {
                irq.Complete(completion);
            }
        }
コード例 #19
0
 private void WriteCompletionMessage(CompletionMessage message, JsonTextWriter writer)
 {
     WriteInvocationId(message, writer);
     if (!string.IsNullOrEmpty(message.Error))
     {
         writer.WritePropertyName(ErrorPropertyName);
         writer.WriteValue(message.Error);
     }
     else if (message.HasResult)
     {
         writer.WritePropertyName(ResultPropertyName);
         PayloadSerializer.Serialize(writer, message.Result);
     }
 }
コード例 #20
0
ファイル: HubEndPoint.cs プロジェクト: YipingRuan/SignalR
 private async Task SendInvocationError(InvocationMessage invocationMessage, HubConnectionContext connection, Type returnType, Exception ex)
 {
     if (!invocationMessage.NonBlocking)
     {
         if (IsIObservable(returnType) || IsChannel(returnType, out _))
         {
             await SendMessageAsync(connection, new StreamCompletionMessage(invocationMessage.InvocationId, ex.Message));
         }
         else
         {
             await SendMessageAsync(connection, CompletionMessage.WithError(invocationMessage.InvocationId, ex.Message));
         }
     }
 }
コード例 #21
0
        private ValueTask CleanupInvocation(HubConnectionContext connection, HubMethodInvocationMessage hubMessage, IHubActivator <THub> hubActivator,
                                            THub hub, IServiceScope scope)
        {
            if (hubMessage.StreamIds != null)
            {
                foreach (var stream in hubMessage.StreamIds)
                {
                    connection.StreamTracker.TryComplete(CompletionMessage.Empty(stream));
                }
            }

            hubActivator?.Release(hub);

            return(scope.DisposeAsync());
        }
コード例 #22
0
 private Task ProcessInvocation(HubConnectionContext connection,
                                HubMethodInvocationMessage hubMethodInvocationMessage, bool isStreamedInvocation)
 {
     if (!_methods.TryGetValue(hubMethodInvocationMessage.Target, out var descriptor))
     {
         // Send an error to the client. Then let the normal completion process occur
         Log.UnknownHubMethod(_logger, hubMethodInvocationMessage.Target);
         return(connection.WriteAsync(CompletionMessage.WithError(
                                          hubMethodInvocationMessage.InvocationId, $"Unknown hub method '{hubMethodInvocationMessage.Target}'")).AsTask());
     }
     else
     {
         return(Invoke(descriptor, connection, hubMethodInvocationMessage, isStreamedInvocation));
     }
 }
コード例 #23
0
        private Task ProcessStreamBindingFailure(HubConnectionContext connection, StreamBindingFailureMessage bindingFailureMessage)
        {
            var errorString = ErrorMessageHelper.BuildErrorMessage(
                "Failed to bind Stream message.",
                bindingFailureMessage.BindingFailure.SourceException, _enableDetailedErrors);

            var message = CompletionMessage.WithError(bindingFailureMessage.Id, errorString);

            Log.ClosingStreamWithBindingError(_logger, message);

            // ignore failure, it means the client already completed the stream or the stream never existed on the server
            connection.StreamTracker.TryComplete(message);

            // TODO: Send stream completion message to client when we add it
            return(Task.CompletedTask);
        }
コード例 #24
0
 private void WriteCompletionMessage(CompletionMessage message, JsonTextWriter writer)
 {
     writer.WriteStartObject();
     WriteHubInvocationMessageCommon(message, writer, HubProtocolConstants.CompletionMessageType);
     if (!string.IsNullOrEmpty(message.Error))
     {
         writer.WritePropertyName(ErrorPropertyName);
         writer.WriteValue(message.Error);
     }
     else if (message.HasResult)
     {
         writer.WritePropertyName(ResultPropertyName);
         PayloadSerializer.Serialize(writer, message.Result);
     }
     writer.WriteEndObject();
 }
コード例 #25
0
ファイル: DefaultHubDispatcher.cs プロジェクト: sk1e/SignalR
        private async Task StreamResultsAsync(string invocationId, HubConnectionContext connection, IAsyncEnumerator <object> enumerator, IServiceScope scope,
                                              IHubActivator <THub> hubActivator, THub hub, CancellationTokenSource streamCts)
        {
            string error = null;

            using (scope)
            {
                try
                {
                    while (await enumerator.MoveNextAsync())
                    {
                        // Send the stream item
                        await connection.WriteAsync(new StreamItemMessage(invocationId, enumerator.Current));
                    }
                }
                catch (ChannelClosedException ex)
                {
                    // If the channel closes from an exception in the streaming method, grab the innerException for the error from the streaming method
                    error = ErrorMessageHelper.BuildErrorMessage("An error occurred on the server while streaming results.", ex.InnerException ?? ex, _enableDetailedErrors);
                }
                catch (Exception ex)
                {
                    // If the streaming method was canceled we don't want to send a HubException message - this is not an error case
                    if (!(ex is OperationCanceledException && connection.ActiveRequestCancellationSources.TryGetValue(invocationId, out var cts) &&
                          cts.IsCancellationRequested))
                    {
                        error = ErrorMessageHelper.BuildErrorMessage("An error occurred on the server while streaming results.", ex, _enableDetailedErrors);
                    }
                }
                finally
                {
                    (enumerator as IDisposable)?.Dispose();

                    hubActivator.Release(hub);

                    // Dispose the linked CTS for the stream.
                    streamCts.Dispose();

                    await connection.WriteAsync(CompletionMessage.WithError(invocationId, error));

                    if (connection.ActiveRequestCancellationSources.TryRemove(invocationId, out var cts))
                    {
                        cts.Dispose();
                    }
                }
            }
        }
コード例 #26
0
        public async Task JoinTeam_TeamDoesNotExist_PlanningPokerException()
        {
            await using var fixture = new PlanningPokerSignalRClientFixture();

            var resultTask = fixture.Target.JoinTeam(PlanningPokerData.TeamName, PlanningPokerData.MemberName, false, fixture.CancellationToken);

            var sentMessage = await fixture.GetSentMessage();

            var invocationId = GetInvocationId(sentMessage);

            var returnMessage = new CompletionMessage(invocationId, "Team 'Test team' does not exist.", null, false);
            await fixture.ReceiveMessage(returnMessage);

            var exception = await Assert.ThrowsExceptionAsync <PlanningPokerException>(() => resultTask);

            Assert.AreEqual("Team 'Test team' does not exist.", exception.Message);
        }
コード例 #27
0
        public async Task JoinTeam_ReturnsEmptyErrorMessage_PlanningPokerException()
        {
            await using var fixture = new PlanningPokerSignalRClientFixture();

            var resultTask = fixture.Target.JoinTeam(PlanningPokerData.TeamName, PlanningPokerData.MemberName, false, fixture.CancellationToken);

            var sentMessage = await fixture.GetSentMessage();

            var invocationId = GetInvocationId(sentMessage);

            var returnMessage = new CompletionMessage(invocationId, "An unexpected error occured. HubException: ", null, false);
            await fixture.ReceiveMessage(returnMessage);

            var exception = await Assert.ThrowsExceptionAsync <PlanningPokerException>(() => resultTask);

            Assert.AreEqual(string.Empty, exception.Message);
        }
コード例 #28
0
        private async Task StreamResultsAsync(string invocationId, HubConnectionContext connection, IAsyncEnumerator <object> enumerator)
        {
            try
            {
                while (await enumerator.MoveNextAsync())
                {
                    // Send the stream item
                    await SendMessageAsync(connection, new StreamItemMessage(invocationId, enumerator.Current));
                }

                await SendMessageAsync(connection, CompletionMessage.Empty(invocationId));
            }
            catch (Exception ex)
            {
                await SendMessageAsync(connection, CompletionMessage.WithError(invocationId, ex.Message));
            }
        }
コード例 #29
0
            public override void Complete(CompletionMessage completionMessage)
            {
                Log.InvocationCompleted(Logger, InvocationId);
                if (completionMessage.Result != null)
                {
                    Log.ReceivedUnexpectedComplete(Logger, InvocationId);
                    _channel.Writer.TryComplete(new InvalidOperationException("Server provided a result in a completion response to a streamed invocation."));
                }

                if (!string.IsNullOrEmpty(completionMessage.Error))
                {
                    Fail(new HubException(completionMessage.Error));
                    return;
                }

                _channel.Writer.TryComplete();
            }
コード例 #30
0
        public async Task CreateTeam_TeamNameExists_PlanningPokerException()
        {
            await using var fixture = new PlanningPokerSignalRClientFixture();

            var resultTask = fixture.Target.CreateTeam(PlanningPokerData.TeamName, PlanningPokerData.ScrumMasterName, Deck.Standard, fixture.CancellationToken);

            var sentMessage = await fixture.GetSentMessage();

            var invocationId = GetInvocationId(sentMessage);

            var returnMessage = new CompletionMessage(invocationId, "An unexpected error occured. HubException: Team 'Test team' already exists.", null, false);
            await fixture.ReceiveMessage(returnMessage);

            var exception = await Assert.ThrowsExceptionAsync <PlanningPokerException>(() => resultTask);

            Assert.AreEqual("Team 'Test team' already exists.", exception.Message);
        }