public override void ChannelWritabilityChanged(IChannelHandlerContext context)
        {
            Debug.Assert(context == _inboundCtx.InnerContext);

            if (!_inboundCtx.Removed)
            {
                InboundHandler.ChannelWritabilityChanged(_inboundCtx);
            }
            else
            {
                _ = _inboundCtx.FireChannelWritabilityChanged();
            }
        }
        public override void ChannelRead(IChannelHandlerContext context, object message)
        {
            Debug.Assert(context == _inboundCtx.InnerContext);

            if (!_inboundCtx.Removed)
            {
                InboundHandler.ChannelRead(_inboundCtx, message);
            }
            else
            {
                _ = _inboundCtx.FireChannelRead(message);
            }
        }
        public override void ChannelReadComplete(IChannelHandlerContext context)
        {
            Debug.Assert(context == _inboundCtx.InnerContext);

            if (!_inboundCtx.Removed)
            {
                InboundHandler.ChannelReadComplete(_inboundCtx);
            }
            else
            {
                _ = _inboundCtx.FireChannelReadComplete();
            }
        }
        public override void UserEventTriggered(IChannelHandlerContext context, object evt)
        {
            Debug.Assert(context == _inboundCtx.InnerContext);

            if (!_inboundCtx.Removed)
            {
                InboundHandler.UserEventTriggered(_inboundCtx, evt);
            }
            else
            {
                _ = _inboundCtx.FireUserEventTriggered(evt);
            }
        }
        public override void ExceptionCaught(IChannelHandlerContext context, Exception exception)
        {
            Debug.Assert(context == _inboundCtx.InnerContext);

            if (!_inboundCtx.Removed)
            {
                InboundHandler.ExceptionCaught(_inboundCtx, exception);
            }
            else
            {
                _ = _inboundCtx.FireExceptionCaught(exception);
            }
        }
        public override void ChannelUnregistered(IChannelHandlerContext context)
        {
            Debug.Assert(context == _inboundCtx.InnerContext);

            if (!_inboundCtx.IsRemoved)
            {
                InboundHandler.ChannelUnregistered(_inboundCtx);
            }
            else
            {
                _ = _inboundCtx.FireChannelUnregistered();
            }
        }
        public void CleanupThrows()
        {
            var decoder        = new CleanupDecoder();
            var inboundHandler = new InboundHandler();
            var channel        = new EmbeddedChannel(decoder, inboundHandler);

            Assert.True(channel.WriteInbound(new DefaultHttpRequest(HttpVersion.Http11, HttpMethod.Get, "/")));
            var content = new DefaultHttpContent(Unpooled.Buffer().WriteZero(10));

            Assert.True(channel.WriteInbound(content));
            Assert.Equal(1, content.ReferenceCount);

            Assert.Throws <DecoderException>(() => channel.FinishAndReleaseAll());
            Assert.Equal(1, inboundHandler.ChannelInactiveCalled);
            Assert.Equal(0, content.ReferenceCount);
        }
        public override void HandlerAdded(IChannelHandlerContext context)
        {
            if (InboundHandler is null)
            {
                ThrowHelper.ThrowInvalidOperationException_InitMustBeInvokedBefore(this);
            }

            _outboundCtx = new DelegatingChannelHandlerContext(context, OutboundHandler);
            _inboundCtx  = new DelegatingChannelHandlerContext(context, InboundHandler, OnExceptionCaught);

            // The inboundCtx and outboundCtx were created and set now it's safe to call removeInboundHandler() and
            // removeOutboundHandler().
            _ = Interlocked.Exchange(ref _handlerAdded, SharedConstants.True);

            try
            {
                InboundHandler.HandlerAdded(_inboundCtx);
            }
            finally
            {
                OutboundHandler.HandlerAdded(_outboundCtx);
            }
        }