コード例 #1
0
        protected virtual Task InitializePersistentState()
        {
            _hostShutdownToken = _context.Environment.GetShutdownToken();

            _requestLifeTime = new HttpRequestLifeTime(this, WriteQueue, Trace, ConnectionId);

            // Create the TCS that completes when the task returned by PersistentConnection.OnConnected does.
            _connectTcs = new DispatchingTaskCompletionSource <object>();

            // Create a token that represents the end of this connection's life
            _connectionEndTokenSource = new SafeCancellationTokenSource();
            _connectionEndToken       = _connectionEndTokenSource.Token;

            // Handle the shutdown token's callback so we can end our token if it trips
            _hostRegistration = _hostShutdownToken.SafeRegister(state =>
            {
                ((SafeCancellationTokenSource)state).Cancel();
            },
                                                                _connectionEndTokenSource);

            // When the connection ends release the request
            _connectionEndRegistration = CancellationToken.SafeRegister(state =>
            {
                ((HttpRequestLifeTime)state).Complete();
            },
                                                                        _requestLifeTime);

            return(InitializeMessageId());
        }
コード例 #2
0
ファイル: Connection.cs プロジェクト: tanluutrong2206/SignalR
        /// <summary>
        /// Starts the <see cref="Connection"/>.
        /// </summary>
        /// <param name="transport">The transport to use.</param>
        /// <returns>A task that represents when the connection has started.</returns>
        public Task Start(IClientTransport transport)
        {
            if (transport == null)
            {
                throw new ArgumentNullException("transport");
            }

            lock (_startLock)
            {
                if (!ChangeState(ConnectionState.Disconnected, ConnectionState.Connecting))
                {
                    return(_connectTask ?? TaskAsyncHelper.Empty);
                }

                _disconnectCts         = new CancellationTokenSource();
                _startTcs              = new DispatchingTaskCompletionSource <object>();
                _receiveQueueMonitor   = new TaskQueueMonitor(this, DeadlockErrorTimeout);
                _receiveQueue          = new TaskQueue(_startTcs.Task, _receiveQueueMonitor);
                _lastQueuedReceiveTask = TaskAsyncHelper.Empty;

                _transport = transport;

                _connectTask = Negotiate(transport);
            }

            return(_connectTask);
        }
コード例 #3
0
        public override Task Send(IConnection connection, string data, string connectionData)
        {
            if (connection == null)
            {
                throw new ArgumentNullException("connection");
            }

            var webSocket = _webSocket;

            if (webSocket == null)
            {
                Exception ex;
                if (connection.State != ConnectionState.Disconnected)
                {
                    // Make this a faulted task and trigger the OnError even to maintain consistency with the HttpBasedTransports
                    ex = new InvalidOperationException(ResourcesStore.GetResourceString("Error_DataCannotBeSentDuringWebSocketReconnect"));
                    connection.OnError(ex);
                }
                else
                {
                    ex = new InvalidOperationException(ResourcesStore.GetResourceString("Error_DataCannotBeSentDuringWebSocketReconnect"));
                }

                var tcs = new DispatchingTaskCompletionSource <object>();
                tcs.SetException(ex);
                return(tcs.Task);
            }

            return(Send(webSocket, data));
        }
コード例 #4
0
ファイル: HubDispatcher.cs プロジェクト: ebt/SignalRSlim
        private Task ExecuteHubEvent(IRequest request, string connectionId, Func <IHub, Task> action)
        {
            var hubs       = GetHubs(request, connectionId).ToList();
            var operations = hubs.Select(instance => action(instance).OrEmpty().Catch(Trace)).ToArray();

            if (operations.Length == 0)
            {
                DisposeHubs(hubs);
                return(TaskAsyncHelper.Empty);
            }

            var tcs = new DispatchingTaskCompletionSource <object>();

            Task.Factory.ContinueWhenAll(operations, tasks =>
            {
                DisposeHubs(hubs);
                var faulted = tasks.FirstOrDefault(t => t.IsFaulted);
                if (faulted != null)
                {
                    tcs.TrySetUnwrappedException(faulted.Exception);
                }
                else if (tasks.Any(t => t.IsCanceled))
                {
                    tcs.TrySetCanceled();
                }
                else
                {
                    tcs.TrySetResult(null);
                }
            });

            return(tcs.Task);
        }
コード例 #5
0
        public virtual Task <int> ExecuteNonQueryAsync()
        {
            var tcs = new DispatchingTaskCompletionSource <int>();

            Execute(cmd => cmd.ExecuteNonQueryAsync(), tcs);
            return(tcs.Task);
        }
コード例 #6
0
 public SendContext(ScaleoutStream stream, Func <object, Task> send, object state)
 {
     Stream = stream;
     TaskCompletionSource = new DispatchingTaskCompletionSource <object>();
     _send  = send;
     _state = state;
 }
コード例 #7
0
        private static Task <T> FromAsync <T>(Func <AsyncCallback, IAsyncResult> begin, Func <IAsyncResult, T> end)
        {
            var tcs = new DispatchingTaskCompletionSource <T>();

            try
            {
                var result = begin(ar =>
                {
                    if (!ar.CompletedSynchronously)
                    {
                        CompleteAsync(tcs, ar, end);
                    }
                });

                if (result.CompletedSynchronously)
                {
                    CompleteAsync(tcs, result, end);
                }
            }
            catch (Exception ex)
            {
                tcs.TrySetException(ex);
            }

            return(tcs.Task);
        }
コード例 #8
0
        private void Execute <T>(Func <IDbCommand, Task <T> > commandFunc, DispatchingTaskCompletionSource <T> tcs)
        {
            IDbConnection connection = null;

            try
            {
                connection = _dbProviderFactory.CreateConnection();
                connection.ConnectionString = ConnectionString;
                var command = CreateCommand(connection);

                connection.Open();

                commandFunc(command)
                .Then(result => tcs.SetResult(result))
                .Catch(ex => tcs.SetUnwrappedException(ex), Trace)
                .Finally(state =>
                {
                    var conn = (DbConnection)state;
                    if (conn != null)
                    {
                        conn.Dispose();
                    }
                }, connection);
            }
            catch (Exception)
            {
                if (connection != null)
                {
                    connection.Dispose();
                }
                throw;
            }
        }
コード例 #9
0
        public static Task <string> ReadAsString(this IResponse response, Func <ArraySegment <byte>, bool> onChunk)
        {
            if (response == null)
            {
                throw new ArgumentNullException("response");
            }

            var stream    = response.GetStream();
            var reader    = new AsyncStreamReader(stream);
            var result    = new StringBuilder();
            var resultTcs = new DispatchingTaskCompletionSource <string>();

            reader.Data = buffer =>
            {
                if (onChunk(buffer))
                {
                    result.Append(Encoding.UTF8.GetString(buffer.Array, buffer.Offset, buffer.Count));
                }
            };

            reader.Closed = exception =>
            {
                response.Dispose();
                resultTcs.TrySetResult(result.ToString());
            };

            reader.Start();

            return(resultTcs.Task);
        }
コード例 #10
0
 public HttpRequestLifeTime(TransportDisconnectBase transport, TaskQueue writeQueue, TraceSource trace, string connectionId)
 {
     _lifetimeTcs  = new DispatchingTaskCompletionSource <object>();
     _transport    = transport;
     _trace        = trace;
     _connectionId = connectionId;
     _writeQueue   = writeQueue;
 }
コード例 #11
0
        public Task StartReceiving()
        {
            var tcs = new DispatchingTaskCompletionSource <object>();

            ThreadPool.QueueUserWorkItem(Receive, tcs);

            return(tcs.Task);
        }
コード例 #12
0
ファイル: AutoTransport.cs プロジェクト: ElectroNis/SignalR
        public Task Start(IConnection connection, string connectionData, CancellationToken disconnectToken)
        {
            var tcs = new DispatchingTaskCompletionSource <object>();

            // Resolve the transport
            ResolveTransport(connection, connectionData, disconnectToken, tcs, _startIndex);

            return(tcs.Task);
        }
コード例 #13
0
 private void Execute <T>(Func <IQuery, Task <T> > commandFunc, DispatchingTaskCompletionSource <T> tcs)
 {
     using (var session = SessionFactoryInfo.SessionFactory.OpenSession())
     {
         var command = CreateCommand(session);
         commandFunc(command)
         .Then(result => tcs.SetResult(result))
         .Catch(ex => tcs.SetUnwrappedException(ex), Trace);
     }
 }
コード例 #14
0
ファイル: HubDispatcher.cs プロジェクト: ebt/SignalRSlim
 // This method is being used to buld a callback with reflection
 private static void ContinueWith <T>(Task <T> task, DispatchingTaskCompletionSource <object> tcs)
 {
     if (task.IsCompleted)
     {
         // Fast path for tasks that completed synchronously
         ContinueSync <T>(task, tcs);
     }
     else
     {
         ContinueAsync <T>(task, tcs);
     }
 }
コード例 #15
0
ファイル: HubDispatcher.cs プロジェクト: ebt/SignalRSlim
        internal static Task <object> Incoming(IHubIncomingInvokerContext context)
        {
            var tcs = new DispatchingTaskCompletionSource <object>();

            try
            {
                object result     = context.MethodDescriptor.Invoker(context.Hub, context.Args.ToArray());
                Type   returnType = context.MethodDescriptor.ReturnType;

                if (typeof(Task).IsAssignableFrom(returnType))
                {
                    var task = (Task)result;
                    if (!returnType.IsGenericType)
                    {
                        task.ContinueWith(tcs);
                    }
                    else
                    {
                        // Get the <T> in Task<T>
                        Type resultType = returnType.GetGenericArguments().Single();

                        Type genericTaskType = typeof(Task <>).MakeGenericType(resultType);

                        // Get the correct ContinueWith overload
                        var parameter = Expression.Parameter(typeof(object));

                        // TODO: Cache this whole thing
                        // Action<object> callback = result => ContinueWith((Task<T>)result, tcs);
                        MethodInfo continueWithMethod = _continueWithMethod.MakeGenericMethod(resultType);

                        Expression body = Expression.Call(continueWithMethod,
                                                          Expression.Convert(parameter, genericTaskType),
                                                          Expression.Constant(tcs));

                        var continueWithInvoker = Expression.Lambda <Action <object> >(body, parameter).Compile();
                        continueWithInvoker.Invoke(result);
                    }
                }
                else
                {
                    tcs.TrySetResult(result);
                }
            }
            catch (Exception ex)
            {
                tcs.TrySetUnwrappedException(ex);
            }

            return(tcs.Task);
        }
コード例 #16
0
        public TransportInitializationHandler(IHttpClient httpClient,
                                              IConnection connection,
                                              string connectionData,
                                              string transport,
                                              CancellationToken disconnectToken,
                                              TransportHelper transportHelper)
        {
            if (connection == null)
            {
                throw new ArgumentNullException("connection");
            }

            _connection      = connection;
            _httpClient      = httpClient;
            _connectionData  = connectionData;
            _transport       = transport;
            _transportHelper = transportHelper;

            _initializationTask    = new DispatchingTaskCompletionSource <object>();
            _initializationInvoker = new ThreadSafeInvoker();

            // Default event
            OnFailure = () => { };

            // We want to fail if the disconnect token is tripped while we're waiting on initialization
            try
            {
                _tokenCleanup = disconnectToken.SafeRegister(
                    _ => Fail(new OperationCanceledException(Resources.Error_ConnectionCancelled, disconnectToken)),
                    state: null);
            }
            catch (ObjectDisposedException)
            {
                // We only dispose this token after cancelling it, so consider this cancellation.
                // The ODE is only thrown on .NET 4.5.2 and below (.NET 4.6 no longer throws ODE from CTS.Register)
                Fail(new OperationCanceledException(Resources.Error_ConnectionCancelled, disconnectToken));
            }

            TaskAsyncHelper.Delay(connection.TotalTransportConnectTimeout)
            .Then(() =>
            {
                // don't timeout once connect request has finished
                if (Interlocked.CompareExchange(ref _state, InitializationState.Failed, InitializationState.Initial) ==
                    InitializationState.Initial)
                {
                    Fail(new TimeoutException(Resources.Error_TransportTimedOutTryingToConnect));
                }
            });
        }
コード例 #17
0
ファイル: HubDispatcher.cs プロジェクト: ebt/SignalRSlim
 private static void ContinueSync <T>(Task <T> task, DispatchingTaskCompletionSource <object> tcs)
 {
     if (task.IsFaulted)
     {
         tcs.TrySetUnwrappedException(task.Exception);
     }
     else if (task.IsCanceled)
     {
         tcs.TrySetCanceled();
     }
     else
     {
         tcs.TrySetResult(task.Result);
     }
 }
コード例 #18
0
 private static void CompleteAsync <T>(DispatchingTaskCompletionSource <T> tcs, IAsyncResult ar, Func <IAsyncResult, T> end)
 {
     try
     {
         tcs.TrySetResult(end(ar));
     }
     catch (OperationCanceledException)
     {
         tcs.TrySetCanceled();
     }
     catch (Exception ex)
     {
         tcs.TrySetException(ex);
     }
 }
コード例 #19
0
ファイル: ScaleoutMessageBus.cs プロジェクト: ebt/SignalRSlim
        /// <summary>
        /// Sends messages to the backplane
        /// </summary>
        /// <param name="messages">The list of messages to send</param>
        /// <returns></returns>
        protected virtual Task Send(IList <Message> messages)
        {
            // If we're only using a single stream then just send
            if (StreamCount == 1)
            {
                return(StreamManager.Send(0, messages));
            }

            var taskCompletionSource = new DispatchingTaskCompletionSource <object>();

            // Group messages by source (connection id)
            var messagesBySource = messages.GroupBy(m => m.Source);

            SendImpl(messagesBySource.GetEnumerator(), taskCompletionSource);

            return(taskCompletionSource.Task);
        }
コード例 #20
0
ファイル: HubDispatcher.cs プロジェクト: ebt/SignalRSlim
 private static void ContinueAsync <T>(Task <T> task, DispatchingTaskCompletionSource <object> tcs)
 {
     task.ContinueWithPreservedCulture(t =>
     {
         if (t.IsFaulted)
         {
             tcs.TrySetUnwrappedException(t.Exception);
         }
         else if (t.IsCanceled)
         {
             tcs.TrySetCanceled();
         }
         else
         {
             tcs.TrySetResult(t.Result);
         }
     });
 }
コード例 #21
0
        public virtual Task <int> ExecuteNonQueryAsync()
        {
            var tcs = new DispatchingTaskCompletionSource <int>();

            return(new Task <int>(() =>
            {
                int a;
                try
                {
                    a = ExecuteNonQuery();
                    tcs.SetResult(a);
                    return a;
                }
                catch (Exception ex)
                {
                    tcs.SetUnwrappedException(ex);
                    throw;
                }
            }));
        }
コード例 #22
0
ファイル: ScaleoutMessageBus.cs プロジェクト: ebt/SignalRSlim
        private void SendImpl(IEnumerator <IGrouping <string, Message> > enumerator, DispatchingTaskCompletionSource <object> taskCompletionSource)
        {
send:

            if (!enumerator.MoveNext())
            {
                taskCompletionSource.TrySetResult(null);
            }
            else
            {
                IGrouping <string, Message> group = enumerator.Current;

                // Get the channel index we're going to use for this message
                int index = (int)((uint)_sipHashBasedComparer.GetHashCode(group.Key) % StreamCount);

                Debug.Assert(index >= 0, "Hash function resulted in an index < 0.");

                Task sendTask = StreamManager.Send(index, group.ToArray()).Catch(_trace);

                if (sendTask.IsCompleted)
                {
                    try
                    {
                        sendTask.Wait();

                        goto send;
                    }
                    catch (Exception ex)
                    {
                        taskCompletionSource.SetUnwrappedException(ex);
                    }
                }
                else
                {
                    sendTask.Then((enumer, tcs) => SendImpl(enumer, tcs), enumerator, taskCompletionSource)
                    .ContinueWithNotComplete(taskCompletionSource);
                }
            }
        }
コード例 #23
0
        public Task <JSONNode> Invoke(string method, Action <JSONNode> onProgress, params object[] args)
        {
            if (method == null)
            {
                throw new ArgumentNullException("method");
            }

            if (args == null)
            {
                throw new ArgumentNullException("args");
            }

            JSONArray ArgsArray = new JSONArray();

            for (int i = 0; i < args.Length; i++)
            {
                ArgsArray.Add(JSON.FromData(args[i]));
            }

            var tcs        = new DispatchingTaskCompletionSource <JSONNode>();
            var callbackId = _connection.RegisterCallback(result =>
            {
                if (result != null)
                {
                    if (result.Error != null)
                    {
                        if (result.IsHubException)
                        {
                            // A HubException was thrown
                            tcs.TrySetException(new HubException(result.Error, result.ErrorData));
                        }
                        else
                        {
                            tcs.TrySetException(new InvalidOperationException(result.Error));
                        }
                    }
                    else
                    {
                        try
                        {
                            if (result.State != null)
                            {
                                foreach (var pair in result.State)
                                {
                                    this[pair.Key] = pair.Value;
                                }
                            }

                            if (result.ProgressUpdate != null)
                            {
                                onProgress?.Invoke(result.ProgressUpdate.Data);
                            }
                            else if (result.Result != null)
                            {
                                tcs.TrySetResult(result.Result);
                            }
                            else
                            {
                                tcs.TrySetResult(new JSONNonexistent());
                            }
                        }
                        catch (Exception ex)
                        {
                            // If we failed to set the result for some reason or to update
                            // state then just fail the tcs.
                            tcs.TrySetUnwrappedException(ex);
                        }
                    }
                }
                else
                {
                    tcs.TrySetCanceled();
                }
            });

            var hubData = new HubInvocation
            {
                Hub        = _hubName,
                Method     = method,
                Args       = ArgsArray,
                CallbackId = callbackId
            };

            if (_state.Count != 0)
            {
                hubData.State = _state;
            }

            var value = hubData.ToJson().Serialize();

            _connection.Send(value).ContinueWith(task =>
            {
                if (task.IsCanceled)
                {
                    _connection.RemoveCallback(callbackId);
                    tcs.TrySetCanceled();
                }
                else if (task.IsFaulted)
                {
                    _connection.RemoveCallback(callbackId);
                    tcs.TrySetUnwrappedException(task.Exception);
                }
            },
                                                 TaskContinuationOptions.NotOnRanToCompletion);

            return(tcs.Task);
        }
コード例 #24
0
ファイル: AutoTransport.cs プロジェクト: ElectroNis/SignalR
        private void ResolveTransport(IConnection connection, string data, CancellationToken disconnectToken, DispatchingTaskCompletionSource <object> tcs, int index)
        {
            // Pick the current transport
            IClientTransport transport = _transports[index];

            transport.Start(connection, data, disconnectToken).ContinueWith(task =>
            {
                if (task.IsFaulted || task.IsCanceled)
                {
                    Exception ex;
                    if (task.IsCanceled)
                    {
                        ex = new OperationCanceledException(Resources.Error_TaskCancelledException);
                    }
                    else
                    {
                        ex = task.Exception.GetBaseException();
                    }

                    connection.Trace(TraceLevels.Events, "Auto: Failed to connect to using transport {0}. {1}", transport.Name, ex);

                    // If that transport fails to initialize, then fallback.
                    // If it is that /start request that failed, do not fallback.
                    var next = index + 1;
                    if (next < _transports.Count && !(ex is StartException))
                    {
                        // Try the next transport
                        ResolveTransport(connection, data, disconnectToken, tcs, next);
                    }
                    else
                    {
                        // If there's nothing else to try then just fail
                        tcs.SetException(ex);
                    }
                }
                else
                {
                    // Set the active transport
                    _transport = transport;

                    // Complete the process
                    tcs.SetResult(null);
                }
            },
                                                                            TaskContinuationOptions.ExecuteSynchronously);
        }
コード例 #25
0
 public LifetimeContext(TransportDisconnectBase transport, DispatchingTaskCompletionSource <object> lifeTimetcs, Exception error)
 {
     _transport   = transport;
     _lifetimeTcs = lifeTimetcs;
     _error       = error;
 }
コード例 #26
0
        public Task <TResult> Invoke <TResult, TProgress>(string method, Action <TProgress> onProgress, params object[] args)
        {
            if (method == null)
            {
                throw new ArgumentNullException("method");
            }

            if (args == null)
            {
                throw new ArgumentNullException("args");
            }

            var tokenifiedArguments = new JToken[args.Length];

            for (int i = 0; i < tokenifiedArguments.Length; i++)
            {
                tokenifiedArguments[i] = args[i] != null
                    ? JToken.FromObject(args[i], JsonSerializer)
                    : JValue.CreateNull();
            }

            var tcs        = new DispatchingTaskCompletionSource <TResult>();
            var callbackId = _connection.RegisterCallback(result =>
            {
                if (result != null)
                {
                    if (result.Error != null)
                    {
                        if (result.IsHubException.HasValue && result.IsHubException.Value)
                        {
                            // A HubException was thrown
                            tcs.TrySetException(new HubException(result.Error, result.ErrorData));
                        }
                        else
                        {
                            tcs.TrySetException(new InvalidOperationException(result.Error));
                        }
                    }
                    else
                    {
                        try
                        {
                            if (result.State != null)
                            {
                                foreach (var pair in result.State)
                                {
                                    this[pair.Key] = pair.Value;
                                }
                            }

                            if (result.ProgressUpdate != null)
                            {
                                onProgress(result.ProgressUpdate.Data.ToObject <TProgress>(JsonSerializer));
                            }
                            else if (result.Result != null)
                            {
                                tcs.TrySetResult(result.Result.ToObject <TResult>(JsonSerializer));
                            }
                            else
                            {
                                tcs.TrySetResult(default(TResult));
                            }
                        }
                        catch (Exception ex)
                        {
                            // If we failed to set the result for some reason or to update
                            // state then just fail the tcs.
                            tcs.TrySetUnwrappedException(ex);
                        }
                    }
                }
                else
                {
                    tcs.TrySetCanceled();
                }
            });

            var hubData = new HubInvocation
            {
                Hub        = _hubName,
                Method     = method,
                Args       = tokenifiedArguments,
                CallbackId = callbackId
            };

            if (_state.Count != 0)
            {
                hubData.State = _state;
            }

            var value = _connection.JsonSerializeObject(hubData);

            _connection.Send(value).ContinueWith(task =>
            {
                if (task.IsCanceled)
                {
                    _connection.RemoveCallback(callbackId);
                    tcs.TrySetCanceled();
                }
                else if (task.IsFaulted)
                {
                    _connection.RemoveCallback(callbackId);
                    tcs.TrySetUnwrappedException(task.Exception);
                }
            },
                                                 TaskContinuationOptions.NotOnRanToCompletion);

            return(tcs.Task);
        }
コード例 #27
0
        private void ResolveTransport(
            IConnection connection,
            string data,
            CancellationToken disconnectToken,
            DispatchingTaskCompletionSource <object> tcs,
            Exception lastError,
            int index)
        {
            IClientTransport transport = null;
            var next = index;

            // Pick the current transport
            while (next < _transports.Count && transport == null)
            {
                var candidateTransport = _transports[next++];

                // If the current transport is WebSockets and it's not supported by the server, try the next transport.
                if (_tryWebSockets || !"webSockets".Equals(candidateTransport.Name, StringComparison.Ordinal))
                {
                    transport = candidateTransport;
                }
            }

            if (transport is null)
            {
                // If there's nothing else to try, then just fail with the error from the last transport.
                // For the lastError to be null, the AutoTransport must have been initialized with an empty transport list or only WebSockets.
                tcs.TrySetException(lastError ?? new Exception(Resources.Error_NoCompatibleTransportFound));
                return;
            }

            transport.Start(connection, data, disconnectToken).ContinueWith(task =>
            {
                if (task.IsFaulted || task.IsCanceled)
                {
                    Exception ex;
                    if (task.IsCanceled)
                    {
                        ex = new OperationCanceledException(Resources.Error_TaskCancelledException);
                    }
                    else
                    {
                        ex = task.Exception.GetBaseException();
                    }

                    connection.Trace(TraceLevels.Events, "Auto: Failed to connect to using transport {0}. {1}", transport.Name, ex);

                    // If that transport fails to initialize, then fallback.
                    // If it is that /start request that failed, do not fallback.
                    if (ex is StartException)
                    {
                        tcs.TrySetException(ex);
                    }
                    else
                    {
                        // Try the next transport
                        ResolveTransport(connection, data, disconnectToken, tcs, ex, next);
                    }
                }
                else
                {
                    // Set the active transport
                    _transport = transport;

                    // Complete the process
                    tcs.TrySetResult(null);
                }
            },
                                                                            TaskContinuationOptions.ExecuteSynchronously);
        }