public async Task <Conversation> StartConversationAsync(TokenParameters tokenParameters = null, CancellationToken cancellationToken = default(CancellationToken))
        {
            if (SocketClient == null)
            {
                throw new InvalidOperationException("Connection is not opened.");
            }

            var request = new StreamingRequest()
            {
                Verb = "POST",
                Path = "/v3/directline/conversations"
            };

            if (tokenParameters != null)
            {
                request.SetBody(tokenParameters);
            }

            var response = await SocketClient.SendAsync(request).ConfigureAwait(false);

            if (response.StatusCode != 200 && response.StatusCode != 201)
            {
                var body = response.ReadBodyAsStringAsync().ConfigureAwait(false);
                var ex   = new OperationException(
                    $"Operation returned an invalid status code '{response.StatusCode}'",
                    response.StatusCode,
                    body);
                throw ex;
            }

            var conversation = await response.ReadBodyAsJsonAsync <Conversation>().ConfigureAwait(false);

            return(conversation);
        }
        public async Task <ResourceResponse> UpdateActivityAsync(string conversationId, string activityId, Activity activity, CancellationToken cancellationToken = default(CancellationToken))
        {
            if (SocketClient == null)
            {
                throw new InvalidOperationException("Connection is not opened.");
            }

            var request = new StreamingRequest()
            {
                Verb = "PUT",
                Path = $"/v3/directline/conversations/{conversationId}/activities/{activityId}"
            };

            request.SetBody(activity);

            var response = await SocketClient.SendAsync(request).ConfigureAwait(false);

            if (response.StatusCode != 200)
            {
                var body = await response.ReadBodyAsStringAsync().ConfigureAwait(false);

                var ex = new OperationException(
                    $"Operation returned an invalid status code '{response.StatusCode}'",
                    response.StatusCode,
                    body);
                throw ex;
            }

            var resourceResponse = await response.ReadBodyAsJsonAsync <ResourceResponse>().ConfigureAwait(false);

            return(resourceResponse);
        }
        public async Task <Conversation> ReconnectToConversationAsync(string conversationId, string watermark = null, CancellationToken cancellationToken = default(CancellationToken))
        {
            if (SocketClient == null)
            {
                throw new InvalidOperationException("Connection is not opened.");
            }

            var response = await SocketClient.SendAsync(new StreamingRequest()
            {
                Verb = "GET",
                Path = $"/v3/directline/conversations/{conversationId}"
            }).ConfigureAwait(false);

            if (response.StatusCode != 200)
            {
                var body = response.ReadBodyAsStringAsync().ConfigureAwait(false);
                var ex   = new OperationException(
                    $"Operation returned an invalid status code '{response.StatusCode}'",
                    response.StatusCode,
                    body);
                throw ex;
            }

            var conversation = await response.ReadBodyAsJsonAsync <Conversation>().ConfigureAwait(false);

            return(conversation);
        }
        public async Task <ResourceResponse> UploadAttachmentsAsync(string conversationId, string userId, CancellationToken cancellationToken = default(CancellationToken), params AttachmentStream[] attachmentStreams)
        {
            if (SocketClient == null)
            {
                throw new InvalidOperationException("Connection is not opened.");
            }

            if (attachmentStreams == null || attachmentStreams.Length == 0)
            {
                throw new InvalidOperationException("Cannot send attachment streams, because no attachments were supplied.");
            }

            var request = new StreamingRequest()
            {
                Verb = "PUT",
                Path = $"/v3/directline/conversations/{conversationId}/users/{userId}/upload"
            };

            foreach (var stream in attachmentStreams)
            {
                var contentStream = new StreamContent(stream.ContentStream);
                contentStream.Headers.TryAddWithoutValidation(HeaderNames.ContentType, stream.ContentType);
                request.AddStream(contentStream);
            }

            var response = await SocketClient.SendAsync(request).ConfigureAwait(false);

            if (response.StatusCode != 200)
            {
                var body = await response.ReadBodyAsStringAsync().ConfigureAwait(false);

                var ex = new OperationException(
                    $"Operation returned an invalid status code '{response.StatusCode}'",
                    response.StatusCode,
                    body);
                throw ex;
            }

            var resourceResponse = await response.ReadBodyAsJsonAsync <ResourceResponse>().ConfigureAwait(false);

            return(resourceResponse);
        }
        public async Task <ResourceResponse> PostActivityAsync(string conversationId, Activity activity, CancellationToken cancellationToken = default(CancellationToken), params AttachmentStream[] attachmentStreams)
        {
            if (SocketClient == null)
            {
                throw new InvalidOperationException("Connection is not opened.");
            }

            var request = new StreamingRequest()
            {
                Verb = "POST",
                Path = $"/v3/directline/conversations/{conversationId}/activities"
            };

            request.SetBody(activity);

            if (attachmentStreams != null && attachmentStreams.Length > 0)
            {
                foreach (var stream in attachmentStreams)
                {
                    var contentStream = new StreamContent(stream.ContentStream);
                    contentStream.Headers.TryAddWithoutValidation(HeaderNames.ContentType, stream.ContentType);
                    request.AddStream(contentStream);
                }
            }

            var response = await SocketClient.SendAsync(request).ConfigureAwait(false);

            if (response.StatusCode != 200 && response.StatusCode != 204)
            {
                var body = await response.ReadBodyAsStringAsync().ConfigureAwait(false);

                var ex = new OperationException(
                    $"Operation returned an invalid status code '{response.StatusCode}'",
                    response.StatusCode,
                    body);
                throw ex;
            }

            var resourceResponse = await response.ReadBodyAsJsonAsync <ResourceResponse>().ConfigureAwait(false);

            return(resourceResponse);
        }