public async Task PostAsync(string encryptedChannelID)
        {
            // 0) Get request body data.
            string bodyStr;

            using (StreamReader reader
                       = new StreamReader(this.Request.Body, Encoding.UTF8, true, 1024, true))
            {
                bodyStr = await reader.ReadToEndAsync();
            }

            // 0) Decrypt the channelID.
            var protector = _dataProtectionProvider.CreateProtector(_encryptionKey);
            var channelID = protector.Unprotect(encryptedChannelID);

            // 1) Deserialize the body to FlowHttpRequestData format, and deserialize comments of the github issue.
            var dataFromRequestString = JsonConvert.DeserializeObject(bodyStr).ToString();

            dataFromRequest = JsonConvert.DeserializeObject <FlowHttpRequestData>(dataFromRequestString);
            commentsOfIssue = JsonConvert.DeserializeObject <List <FlowGitHubComment> >(dataFromRequest.Comments);

            // 2) Get the conversation reference from the database.
            var databaseName = _config["CosmosDBDatabaseName"];
            var conversationReferenceCollectionName = _config["CosmosConversationReferenceCollection"];

            FeedOptions queryOptions = new FeedOptions {
                EnableCrossPartitionQuery = true
            };
            var lookupQuery1 = _documentClient.CreateDocumentQuery <ConversationReferenceData>(
                UriFactory.CreateDocumentCollectionUri(databaseName, conversationReferenceCollectionName), queryOptions)
                               .Where(c => c.ChannelID == channelID);

            var match = lookupQuery1.ToList();
            var localConversationReferenceData = match[0];
            var cachedConversationReference    = localConversationReferenceData.ChannelConversationReferenceObject;

            // 3) Call an appropriate callback.
            var messageIdCollectionName = _config["CosmosMessageIdCollection"];
            var lookupQuery2            = _documentClient.CreateDocumentQuery <ReplyChainData>(
                UriFactory.CreateDocumentCollectionUri(databaseName, messageIdCollectionName), queryOptions)
                                          .Where(r => r.ExternalTicketId == dataFromRequest.Id);

            // For one external ticket id, there should be one messageID.
            var messageID = lookupQuery2.ToList();

            if (messageID.Count > 0)
            {
                // If this ticket already exists, update the previously sent card and send a reply indicating the card is updated.
                await((BotAdapter)Adapter).ContinueConversationAsync(_appId, cachedConversationReference, BotCallbackForUpdate, default(CancellationToken));
            }
            else
            {
                // If this ticket is new, create a new card and mention people in a reply.
                await((BotAdapter)Adapter).ContinueConversationAsync(_appId, cachedConversationReference, BotCallbackForSend, default(CancellationToken));
            }
        }
        // This function gets invoked when an issue is re-opened, closed or a comment was made.
        private async Task CreateReplyForUpdate(ITurnContext turnContext, string messageId,
                                                FlowHttpRequestData dataFromRequest, CancellationToken cancellationToken)
        {
            // To create a reply chain, it is necessary to have 'messageID' in the
            // ID of the given activity's conversation reference object.
            // This mesageID is used to identify which message to follow up.
            string firstConversationId = OriginalConversationId(turnContext);

            UpdateConversationIdForReplyChain(turnContext, firstConversationId, messageId);

            await ShowUpdatedStatusAndCommentsInReply(turnContext, cancellationToken);

            // As this turncontext is global (this is created from the one
            // conversation reference object we save when the bot is installed),
            // we need to update the id of its activity's conversation reference
            // object so other newly created cards can create replies properly.
            // If we don't have this line, the request will have an incorrect
            // form, eventually causing 502 internal server error.
            turnContext.Activity.GetConversationReference().Conversation.Id = firstConversationId;
        }