Inheritance: NotifyPropertyChanged
        private async Task <int> ForwardBytesAsync(
            LogInfo logInfo,
            string direction,
            ConnectionViewModel readConnection,
            ConnectionViewModel writeConnection,
            byte[] buffer,
            int offset,
            int count,
            CancellationToken cancellationToken)
        {
            var result = await readConnection.Client.GetStream().ReadAsync(buffer, offset, count, cancellationToken);

            await this.logQueue.Enqueue(
                () => Task.Run(() => logInfo.Logger.LogData("RawData", direction, buffer, 0, result)));

            await writeConnection.Client.GetStream().WriteAsync(buffer, offset, result, cancellationToken);

            readConnection.AddBytesReceived(result);
            return(result);
        }
        private async Task ForwardAsync(
            ConnectionViewModel readConnection,
            ConnectionViewModel writeConnection,
            LogInfo logInfo,
            string shortDirection,
            string direction)
        {
            var payloadStream = new MemoryStream();
            var buffer        = new byte[8192];
            var s101Reader    = new S101Reader(
                (b, o, c, t) => this.ForwardBytesAsync(logInfo, direction, readConnection, writeConnection, b, o, c, t));
            Func <LogInfo, OutOfFrameByteReceivedEventArgs, EventInfo> logOutOfFrame =
                (i, e) => i.Logger.LogData("OutOfFrameByte", direction, new[] { e.Value }, 0, 1);
            EventHandler <OutOfFrameByteReceivedEventArgs> handler = async(s, e) =>
                                                                     await this.EnqueueLogOperationAsync(logInfo, "OOFB", shortDirection, null, i => logOutOfFrame(i, e));

            try
            {
                s101Reader.OutOfFrameByteReceived += handler;

                while (await s101Reader.ReadAsync(CancellationToken.None))
                {
                    payloadStream.SetLength(0);
                    int read;

                    while ((read = await s101Reader.Payload.ReadAsync(buffer, 0, buffer.Length)) > 0)
                    {
                        payloadStream.Write(buffer, 0, read);
                    }

                    var type    = GetShortType(s101Reader.Message.Command.ToString());
                    var message = s101Reader.Message;
                    var payload = payloadStream.ToArray();
                    var length  = payload.Length;

                    if (length > 0)
                    {
                        await this.logQueue.Enqueue(
                            () => Task.Run(() => logInfo.Logger.LogData("DecodedPayload", direction, payload, 0, length)));
                    }

                    await this.EnqueueLogOperationAsync(
                        logInfo, type, shortDirection, length, i => i.Logger.LogMessage(direction, message, payload));
                }

                await s101Reader.DisposeAsync(CancellationToken.None);
            }
            catch (ObjectDisposedException)
            {
            }
            catch (Exception ex)
            {
                await this.EnqueueLogOperationAsync(
                    logInfo, "Exception", shortDirection, null, i => i.Logger.LogException(direction, ex));
            }
            finally
            {
                s101Reader.OutOfFrameByteReceived -= handler;
                payloadStream.Dispose();
                writeConnection.Client.Close();
                readConnection.Client.Close();
            }
        }