/// <summary>
 ///		Process request message before deserialization.
 /// </summary>
 /// <param name="context">Context information of deserializing message.</param>
 protected abstract void ProcessCore( RequestMessageDeserializationContext context );
        private static void DeserializeCore( RequestMessageDeserializationContext context )
        {
            using ( var unpacker = new Unpacker( context.ReadBytes() ) )
            {
                var request = unpacker.UnpackObject();
                if ( request == null )
                {
                    if ( context.SerializationError.IsSuccess )
                    {
                        // Since entire stream was readed and its length was in quota, the stream may be coruppted.
                        context.SetSerializationError( new RpcErrorMessage( RpcError.MessageRefusedError, "Invalid message.", "Cannot deserialize message stream." ) );
                    }

                    return;
                }

                if ( !request.Value.IsTypeOf<IList<MessagePackObject>>().GetValueOrDefault() )
                {
                    context.SetSerializationError( new RpcErrorMessage( RpcError.MessageRefusedError, "Invalid message.", "Request message is not array." ) );
                    return;
                }

                var requestFields = request.Value.AsList();
                if ( requestFields.Count > 4 || requestFields.Count < 3 )
                {
                    context.SetSerializationError( new RpcErrorMessage( RpcError.MessageRefusedError, "Invalid message.", "Request message is not 3 nor 4 element array." ) );
                    return;
                }

                if ( !requestFields[ 0 ].IsTypeOf<int>().GetValueOrDefault() )
                {
                    context.SetSerializationError( new RpcErrorMessage( RpcError.MessageRefusedError, "Invalid message.", "Message type of request message is not int 32." ) );
                    return;
                }

                int nextPosition = 1;
                switch ( ( MessageType )requestFields[ 0 ].AsInt32() )
                {
                    case MessageType.Request:
                    {
                        if ( !requestFields[ nextPosition ].IsTypeOf<uint>().GetValueOrDefault() )
                        {
                            context.SetSerializationError( new RpcErrorMessage( RpcError.MessageRefusedError, "Invalid message.", "Message ID of request message is not uint32." ) );
                            return;
                        }

                        // For CLS compliance store uint32 value as int32.
                        unchecked
                        {
                            context.MessageId = ( int )requestFields[ nextPosition ].AsUInt32();
                        }

                        nextPosition++;
                        break;
                    }
                    case MessageType.Notification:
                    {
                        break;
                    }
                    default:
                    {
                        context.SetSerializationError( new RpcErrorMessage( RpcError.MessageRefusedError, "Invalid message.", "Message type of request message is not Request(0) nor Notification(2)." ) );
                        return;
                    }
                }

                if ( !requestFields[ nextPosition ].IsTypeOf<string>().GetValueOrDefault() )
                {
                    context.SetSerializationError( new RpcErrorMessage( RpcError.MessageRefusedError, "Invalid message.", String.Format( CultureInfo.CurrentCulture, "Method of request message (ID:{0}) is not raw. ", context.MessageId ) ) );
                    return;
                }

                try
                {
                    context.MethodName = MessagePackConvert.DecodeStringStrict( requestFields[ nextPosition ].AsBinary() );
                }
                catch ( InvalidOperationException ex )
                {
                    context.SetSerializationError( new RpcErrorMessage( RpcError.MessageRefusedError, "Invalid message.", String.Format( CultureInfo.CurrentCulture, "Message ID:{0}: {1}", context.MessageId, ex.Message ) ) );
                    return;
                }

                nextPosition++;

                if ( !requestFields[ nextPosition ].IsTypeOf<IList<MessagePackObject>>().GetValueOrDefault() )
                {
                    context.SetSerializationError( new RpcErrorMessage( RpcError.MessageRefusedError, "Invalid message.", String.Format( CultureInfo.CurrentCulture, "Arguments of request message (ID:{0}) is not array.", context.MessageId ) ) );
                    return;
                }

                context.Arguments = requestFields[ nextPosition ].AsList();
            }
        }
        /// <summary>
        ///		Process request message before deserialization.
        /// </summary>
        /// <param name="context">Context information of deserializing message.</param>
        internal void Process( RequestMessageDeserializationContext context )
        {
            Contract.Assert( context != null );

            this.ProcessCore( context );
        }
        /// <summary>
        ///		Deserialize from specified buffer.
        /// </summary>
        /// <param name="input">Buffer which stores serialized request/notification stream.</param>
        /// <param name="result">Deserialied packed message will be stored.</param>
        /// <returns>Error information.</returns>
        /// <exception cref="ArgumentNullException">
        ///		<paramref name="input"/> is null.
        /// </exception>
        /// <exception cref="InvalidOperationException">
        ///		Some filters violate contract.
        /// </exception>
        public RpcErrorMessage Deserialize( IEnumerable<byte> input, out RequestMessage result )
        {
            if ( input == null )
            {
                throw new ArgumentNullException( "input" );
            }

            Contract.EndContractBlock();

            var context = new RequestMessageDeserializationContext( input, this._maxRequestLength );

            var sequence = context.ReadBytes();

            foreach ( var preDeserializationFilter in this._preDeserializationFilters )
            {
                sequence = preDeserializationFilter.GetFilter().Process( sequence, context );
                if ( !context.SerializationError.IsSuccess )
                {
                    result = default( RequestMessage );
                    return context.SerializationError;
                }
            }

            DeserializeCore( context );

            if ( !context.SerializationError.IsSuccess )
            {
                result = default( RequestMessage );
                return context.SerializationError;
            }

            Contract.Assert( !String.IsNullOrWhiteSpace( context.MethodName ) );
            Contract.Assert( context.Arguments != null );

            foreach ( var postDeserializationFilter in this._postDeserializationFilters )
            {
                postDeserializationFilter.GetFilter().Process( context );
                if ( !context.SerializationError.IsSuccess )
                {
                    result = default( RequestMessage );
                    return context.SerializationError;
                }
            }

            if ( String.IsNullOrWhiteSpace( context.MethodName ) )
            {
                throw new InvalidOperationException( "Filter became method null or empty." );
            }

            if ( context.Arguments == null )
            {
                throw new InvalidOperationException( "Filter became arguments null." );
            }

            result = new RequestMessage( context.MessageId, context.MethodName, context.Arguments );
            return RpcErrorMessage.Success;
        }