Example #1
0
        /// <summary>
        /// Begins listening for client connections in a separate background thread.
        /// This method waits when pipe will be created(or throws exception).
        /// </summary>
        /// <exception cref="InvalidOperationException"></exception>
        /// <exception cref="IOException"></exception>
        public async Task StartAsync(CancellationToken cancellationToken = default)
        {
            if (IsStarted)
            {
                throw new InvalidOperationException("Server already started");
            }

            await StopAsync(cancellationToken);

            var source = new TaskCompletionSource <bool>();

            using var registration = cancellationToken.Register(() => source.TrySetCanceled(cancellationToken));

            ListenWorker = new TaskWorker(async token =>
            {
                while (!token.IsCancellationRequested)
                {
                    try
                    {
                        var connectionPipeName = $"{PipeName}_{++NextPipeId}";

                        // Send the client the name of the data pipe to use
                        try
                        {
#if NETSTANDARD2_0
                            using var serverStream = CreatePipeStreamFunc?.Invoke(PipeName) ?? PipeServerFactory.Create(PipeName);
#else
                            await using var serverStream = CreatePipeStreamFunc?.Invoke(PipeName) ?? PipeServerFactory.Create(PipeName);
#endif
                            PipeStreamInitializeAction?.Invoke(serverStream);

                            source.TrySetResult(true);

                            await serverStream.WaitForConnectionAsync(token).ConfigureAwait(false);

                            await using var handshakeWrapper = new PipeStreamWrapper(serverStream);

                            await handshakeWrapper.WriteAsync(Encoding.UTF8.GetBytes(connectionPipeName), token)
                            .ConfigureAwait(false);
                        }
                        catch (Exception exception)
                        {
                            if (WaitFreePipe)
                            {
                                throw;
                            }

                            source.TrySetException(exception);
                            break;
                        }

                        // Wait for the client to connect to the data pipe
                        var connectionStream = CreatePipeStreamFunc?.Invoke(connectionPipeName) ?? PipeServerFactory.Create(connectionPipeName);

                        PipeStreamInitializeAction?.Invoke(connectionStream);

                        try
                        {
                            await connectionStream.WaitForConnectionAsync(token).ConfigureAwait(false);
                        }
                        catch
                        {
#if NETSTANDARD2_0
                            connectionStream.Dispose();
#else
                            await connectionStream.DisposeAsync().ConfigureAwait(false);
#endif

                            throw;
                        }

                        // Add the client's connection to the list of connections
                        var connection                = ConnectionFactory.Create <T>(connectionStream, Formatter);
                        connection.MessageReceived   += (sender, args) => OnMessageReceived(args);
                        connection.Disconnected      += (sender, args) => OnClientDisconnected(args);
                        connection.ExceptionOccurred += (sender, args) => OnExceptionOccurred(args.Exception);
                        connection.Start();

                        Connections.Add(connection);

                        OnClientConnected(new ConnectionEventArgs <T>(connection));
                    }
                    catch (OperationCanceledException)
                    {
                        throw;
                    }
                    // Catch the IOException that is raised if the pipe is broken or disconnected.
                    catch (IOException)
                    {
                        await Task.Delay(TimeSpan.FromMilliseconds(1), token).ConfigureAwait(false);
                    }
                    catch (Exception exception)
                    {
                        OnExceptionOccurred(exception);
                        break;
                    }
                }
            }, OnExceptionOccurred);

            try
            {
                await source.Task.ConfigureAwait(false);
            }
            catch (Exception)
            {
                await StopAsync(cancellationToken);

                throw;
            }
        }
Example #2
0
        /// <summary>
        /// Begins listening for client connections in a separate background thread.
        /// This method waits when pipe will be created(or throws exception).
        /// </summary>
        /// <exception cref="InvalidOperationException"></exception>
        /// <exception cref="IOException"></exception>
        public async Task StartAsync(CancellationToken cancellationToken = default)
        {
            if (IsStarted)
            {
                throw new InvalidOperationException("Server already started");
            }

            await StopAsync(cancellationToken);

            var source = new TaskCompletionSource <bool>();

            using var registration = cancellationToken.Register(() => source.TrySetCanceled(cancellationToken));

            ListenWorker = new TaskWorker(async token =>
            {
                while (!token.IsCancellationRequested)
                {
                    try
                    {
                        if (Connection != null && Connection.IsConnected)
                        {
                            await Task.Delay(TimeSpan.FromMilliseconds(1), cancellationToken).ConfigureAwait(false);
                            continue;
                        }

                        if (Connection != null)
                        {
                            await Connection.DisposeAsync().ConfigureAwait(false);
                        }

                        // Wait for the client to connect to the data pipe
                        var connectionStream = CreatePipeStreamFunc?.Invoke(PipeName) ?? PipeServerFactory.Create(PipeName);

                        try
                        {
                            PipeStreamInitializeAction?.Invoke(connectionStream);

                            source.TrySetResult(true);

                            await connectionStream.WaitForConnectionAsync(token).ConfigureAwait(false);
                        }
                        catch
                        {
#if NETSTANDARD2_0
                            connectionStream.Dispose();
#else
                            await connectionStream.DisposeAsync().ConfigureAwait(false);
#endif

                            throw;
                        }

                        var connection = ConnectionFactory.Create <T>(connectionStream, Formatter);
                        try
                        {
                            connection.MessageReceived   += (sender, args) => OnMessageReceived(args);
                            connection.Disconnected      += (sender, args) => OnClientDisconnected(args);
                            connection.ExceptionOccurred += (sender, args) => OnExceptionOccurred(args.Exception);
                            connection.Start();
                        }
                        catch
                        {
                            await connection.DisposeAsync().ConfigureAwait(false);

                            throw;
                        }

                        Connection = connection;

                        OnClientConnected(new ConnectionEventArgs <T>(connection));
                    }
                    catch (OperationCanceledException)
                    {
                        if (Connection != null)
                        {
                            await Connection.DisposeAsync().ConfigureAwait(false);

                            Connection = null;
                        }
                        throw;
                    }
                    // Catch the IOException that is raised if the pipe is broken or disconnected.
                    catch (IOException exception)
                    {
                        if (!WaitFreePipe)
                        {
                            source.TrySetException(exception);
                            break;
                        }

                        await Task.Delay(TimeSpan.FromMilliseconds(1), token).ConfigureAwait(false);
                    }
                    catch (Exception exception)
                    {
                        OnExceptionOccurred(exception);
                        break;
                    }
                }
            }, OnExceptionOccurred);

            try
            {
                await source.Task.ConfigureAwait(false);
            }
            catch (Exception)
            {
                await StopAsync(cancellationToken);

                throw;
            }
        }