public async Task <BuildRequest> ReadBuildRequestAsync(CancellationToken cancellationToken)
        {
            var request = await BuildRequest.ReadAsync(Stream, cancellationToken).ConfigureAwait(false);

            // Now that we've read data from the stream we can validate the identity.
            if (!NamedPipeUtil.CheckClientElevationMatches(Stream))
            {
                throw new Exception("Client identity does not match server identity.");
            }

            // The result is deliberately discarded here. The idea is to kick off the monitor code and
            // when it completes it will trigger the task. Don't want to block on that here.
            _ = MonitorDisconnect();

            return(request);

            async Task MonitorDisconnect()
            {
                try
                {
                    await BuildServerConnection.MonitorDisconnectAsync(Stream, request.RequestId, Logger, DisconnectCancellationTokenSource.Token).ConfigureAwait(false);
                }
                catch (Exception ex)
                {
                    Logger.LogException(ex, $"Error monitoring disconnect {request.RequestId}");
                }
                finally
                {
                    DisconnectTaskCompletionSource.TrySetResult(this);
                }
            }
        }
        public void Dispose()
        {
            if (!IsDisposed)
            {
                try
                {
                    DisconnectTaskCompletionSource.TrySetResult(new object());
                    DisconnectCancellationTokenSource.Cancel();
                    Stream.Close();
                }
                catch (Exception ex)
                {
                    Logger.LogException(ex, $"Error closing client connection");
                }

                IsDisposed = true;
            }
        }