public void TestPrepare_SetAsNotification_SendingBufferAndSessionAreSet()
        {
            var target = new ClientRequestContext();

            target.SetNotification("A", (_0, _1) => { });
            var oldSessionId = target.SessionId;

            target.Prepare(true);
            Assert.That(target.SendingBuffer.All(segment => segment.Array != null), Is.Not.Null);
            Assert.That(target.BufferList, Is.SameAs(target.SendingBuffer));
        }
		public void TestPrepare_SetAsNotification_SendingBufferAndSessionAreSet()
		{
			var target = new ClientRequestContext();
			target.SetNotification( "A", ( _0, _1 ) => { } );
			var oldSessionId = target.SessionId;

			target.Prepare( true );
			Assert.That( target.SendingBuffer.All( segment => segment.Array != null ), Is.Not.Null );
			Assert.That( target.BufferList, Is.SameAs( target.SendingBuffer ) );
		}
        /// <summary>
        ///		Sends a request or notification message with the specified context.
        /// </summary>
        /// <param name="context">The context information.</param>
        /// <exception cref="ArgumentNullException">
        ///		<paramref name="context"/> is <c>null</c>.
        /// </exception>
        /// <exception cref="ArgumentException">
        ///		<paramref name="context"/> is not bound to this transport.
        /// </exception>
        /// <exception cref="ObjectDisposedException">
        ///		This instance has been disposed.
        /// </exception>
        /// <exception cref="InvalidOperationException">
        ///		This instance is in shutdown.
        ///		Or the message ID or session ID is duplicated.
        /// </exception>
        /// <exception cref="RpcException">
        ///		Failed to send request or notification to the server.
        /// </exception>
        public void Send(ClientRequestContext context)
        {
            if (context == null)
            {
                throw new ArgumentNullException("context");
            }

            if (!Object.ReferenceEquals(context.BoundTransport, this))
            {
                throw new ArgumentException("Context is not bound to this object.", "context");
            }

            this.VerifyIsNotDisposed();

            if (this.IsClientShutdown)
            {
                throw new InvalidOperationException("This transport is in shutdown.");
            }

            Contract.EndContractBlock();

            if (this.IsServerShutdown)
            {
                throw new RpcErrorMessage(RpcError.TransportError, "Server did shutdown socket.", null).ToException();
            }

            context.Prepare(this.CanUseChunkedBuffer);

            if (context.MessageType == MessageType.Request)
            {
                if (!this._pendingRequestTable.TryAdd(context.MessageId.Value, context.RequestCompletionCallback))
                {
                    throw new InvalidOperationException(String.Format(CultureInfo.CurrentCulture, "Message ID '{0}' is already used.", context.MessageId));
                }
            }
            else
            {
                if (!this._pendingNotificationTable.TryAdd(context.SessionId, context.NotificationCompletionCallback))
                {
                    throw new InvalidOperationException(String.Format(CultureInfo.CurrentCulture, "Session ID '{0}' is already used.", context.MessageId));
                }
            }

            if (MsgPackRpcClientProtocolsTrace.ShouldTrace(MsgPackRpcClientProtocolsTrace.SendOutboundData))
            {
                var socket = this.BoundSocket;
                MsgPackRpcClientProtocolsTrace.TraceEvent(
                    MsgPackRpcClientProtocolsTrace.SendOutboundData,
                    "Send request/notification. {{ \"SessionID\" : {0}, \"Socket\" : 0x{1:X}, \"RemoteEndPoint\" : \"{2}\", \"LocalEndPoint\" : \"{3}\", \"Type\" : \"{4}\", \"MessageID\" : {5}, \"Method\" : \"{6}\", \"BytesTransferring\" : {7} }}",
                    context.SessionId,
                    GetHandle(socket),
                    GetRemoteEndPoint(socket, context),
                    GetLocalEndPoint(socket),
                    context.MessageType,
                    context.MessageId,
                    context.MethodName,
                    context.SendingBuffer.Sum(segment => ( long )segment.Count)
                    );
            }

            // Because exceptions here means client error, it should be handled like other client error.
            // Therefore, no catch clauses here.
            ApplyFilters(this._afterSerializationFilters, context);

            if (this.Manager.Configuration.WaitTimeout != null)
            {
                context.Timeout += this.OnSendTimeout;
                context.StartWatchTimeout(this.Manager.Configuration.WaitTimeout.Value);
            }

            this.SendCore(context);
        }