Search code examples
c#botframework

WaterfallDialog choiceprompt working in emulator but not working in directline webchannel in Bot framework v4


I have recently migrated my project from bot framework v3 to bot V4. I have FeedbackDialog file in this i have implemented waterfallsteps, choiceprompts. Everything and the flow is working correctly in Emulator. But it is not working properly means the flow is not working fine in Webchannel Please provide the solution to this problem.

Here is my code.

public FeedbackDialog() : base(nameof(FeedbackDialog))
    {
        AddDialog(new ChoicePrompt("ShowChoicePrompt") { Style = ListStyle.HeroCard });
        AddDialog(new ChoicePrompt(nameof(ConfirmPrompt)));
        AddDialog(new WaterfallDialog(nameof(WaterfallDialog), new WaterfallStep[]
       {
            StartAsync,
            MessageReceivedAsync,
            ResumeAfterPositiveFeedbackSelectionClarification
       }));

         InitialDialogId = nameof(WaterfallDialog);
    }

    public async Task<DialogTurnResult> StartAsync(WaterfallStepContext stepContext, CancellationToken cancellationToken)

    {

        var reply = ((Activity)stepContext.Context.Activity).CreateReply(BotConstants.feedbackRequestText);

        reply.SuggestedActions = new SuggestedActions()
        {
            Actions = new List<CardAction>()
            {
                new CardAction(){ Title = "👍", Type=ActionTypes.PostBack, Value=BotConstants.positiveFeedbackValue },
                new CardAction(){ Title = "👎", Type=ActionTypes.PostBack, Value=BotConstants.negativeFeedbackValue }
            }
        };
        await stepContext.Context.SendActivityAsync(reply, cancellationToken);
        return new DialogTurnResult(DialogTurnStatus.Waiting);
        // return await stepContext.PromptAsync(nameof(ConfirmPrompt), promptOptions, cancellationToken);

    }

    public async Task<DialogTurnResult> MessageReceivedAsync(WaterfallStepContext stepContext, CancellationToken cancellationToken)
    {
        var data=stepContext.Result;
        var res = stepContext.Result;
       // string res= Convert.ToString(data.GetType().GetProperty("Synonym").GetValue(data, null));
        var feedbackDetails = (FeedbackData)stepContext.Options;

        var userFeedback =Convert.ToString(res);
       // var userFeedback = feedbackDetails.userFeedback;
        string userQuestion = feedbackDetails.userQuestion;
        string intent = feedbackDetails.intent;
        int Id = feedbackDetails.Id;

        if (userFeedback.Contains(BotConstants.positiveFeedbackValue) || userFeedback.Contains(BotConstants.negativeFeedbackValue))
        {
            // create telemetry client to post to Application Insights 
            TelemetryClient telemetry = new TelemetryClient();
            telemetry.InstrumentationKey = Configuration.CDPOSConfigurationManager.GetAppSetting("InstrumentationKey");
            RequestRepository requestRepository = new RequestRepository();

            if (userFeedback.Contains(BotConstants.positiveFeedbackValue))
            {
                // post feedback to App Insights
                var properties = new Dictionary<string, string>
                {
                    {"Question", userQuestion },
                    {"LuisIntent", intent },
                    {"Vote", "Yes" }
                    // add properties relevant to your bot 
                };

                telemetry.TrackEvent("Yes-Vote", properties);

                var chatFeedback = true;
                //requestRepository.AddChatbotEntryToDB(userQuestion, intent, chatFeedback);
                requestRepository.updateChatFeedbackStatus(Id, chatFeedback);

                var options = BotConstants.positiveFeedbackOption;
                var descriptions = BotConstants.positiveFeedbackOptionDesc;
                Activity textPrompt = stepContext.Context.Activity.CreateReply(BotConstants.positiveFeedbackResponse);


                List<Microsoft.Bot.Builder.Dialogs.Choices.Choice> choices = new List<Microsoft.Bot.Builder.Dialogs.Choices.Choice>()
                {
                       new Microsoft.Bot.Builder.Dialogs.Choices.Choice { Value = BotConstants.YeshaveAnotherQuestionOption, Synonyms = new List<string> { "Yes" } },
                       new Microsoft.Bot.Builder.Dialogs.Choices.Choice { Value = BotConstants.NothankyouOption, Synonyms = new List<string> { "No" }}
                };

                try
                {
                    await stepContext.PromptAsync("ShowChoicePrompt", new PromptOptions {Prompt= MessageFactory.Text(BotConstants.positiveFeedbackResponse), Choices= choices }, cancellationToken);
                    return new DialogTurnResult(DialogTurnStatus.Waiting);
                }

                catch (Exception ex)
                {
                    await stepContext.PromptAsync("ShowChoicePrompt", new PromptOptions { Prompt = MessageFactory.Text(BotConstants.positiveFeedbackResponse), Choices = choices }, cancellationToken);
                    return new DialogTurnResult(DialogTurnStatus.Waiting);
                }

            }
            else if (userFeedback.Contains(BotConstants.negativeFeedbackValue))
            {
                var properties = new Dictionary<string, string>
                {
                    {"Question", userQuestion },
                    {"LuisIntent", intent },
                    {"Vote", "Yes" }
                    // add properties relevant to your bot 
                };

                telemetry.TrackEvent("No-Vote", properties);
                var chatFeedback = false;

                //requestRepository.AddChatbotEntryToDB(userQuestion, intent, chatFeedback);
                requestRepository.updateChatFeedbackStatus(Id, chatFeedback);
                await stepContext.Context.SendActivityAsync(BotConstants.negativeFeedbackResponse);
                await stepContext.Context.SendActivityAsync(BotConstants.logTicketResponse);


                var options = BotConstants.negativeFeedbackOption;
                var descriptions = BotConstants.negativeFeedbackDesc;


                List<Microsoft.Bot.Builder.Dialogs.Choices.Choice> NegativeChoices = new List<Microsoft.Bot.Builder.Dialogs.Choices.Choice>()
                {
                       new Microsoft.Bot.Builder.Dialogs.Choices.Choice { Value = BotConstants.logTicket, Synonyms = new List<string> { BotConstants.logTicketOption } },
                       new Microsoft.Bot.Builder.Dialogs.Choices.Choice { Value = BotConstants.rephraseQuestionOption, Synonyms = new List<string> { BotConstants.rephraseQuestionOption }}
                };

                try
                {

                    await stepContext.PromptAsync("ShowChoicePrompt", new PromptOptions { Prompt = MessageFactory.Text(BotConstants.positiveFeedbackResponse), Choices = NegativeChoices }, cancellationToken);
                    return new DialogTurnResult(DialogTurnStatus.Waiting);

                }

                catch (Exception ex)
                {
                    await stepContext.PromptAsync("ShowChoicePrompt", new PromptOptions { Prompt = MessageFactory.Text(BotConstants.question), Choices = NegativeChoices }, cancellationToken);
                    return new DialogTurnResult(DialogTurnStatus.Waiting);
                }
            }
        }
        else
        {
            return await stepContext.BeginDialogAsync(nameof(RootDialog), null, cancellationToken);
            // no feedback, return to main dialog
           // return await stepContext.EndDialogAsync(userFeedback, cancellationToken);
            //return stepContext.BeginDialogAsync(userFeedback, cancellationToken);
        }
        return await stepContext.EndDialogAsync(userFeedback, cancellationToken);
    }

    private async Task<DialogTurnResult> ResumeAfterPositiveFeedbackSelectionClarification(WaterfallStepContext stepContext, CancellationToken cancellationToken)
    {
        var data = stepContext.Result;
        if (stepContext.Result != null)
        {
            string selection = Convert.ToString(data.GetType().GetProperty("Synonym").GetValue(data, null));
            // var selection = stepContext.Result;
            if (selection == BotConstants.YeshaveAnotherQuestionOption || selection == BotConstants.haveAnotherQuestionOption || selection == BotConstants.rephraseQuestionOption)
            {
                await stepContext.Context.SendActivityAsync(BotConstants.askAnotherQuestion);
            }
            else
            {
                await stepContext.Context.SendActivityAsync(BotConstants.logaTicketResponse);
            }
        }
       return await stepContext.EndDialogAsync(null, cancellationToken);
    }









public static void Register(HttpConfiguration config)
            {
                var builder = new ContainerBuilder();
               // builder.RegisterApiControllers(Assembly.GetExecutingAssembly());
                builder.RegisterType<MessagesController>().InstancePerRequest();
                // The ConfigurationCredentialProvider will retrieve the MicrosoftAppId and
                // MicrosoftAppPassword from Web.config
                builder.RegisterType<ConfigurationCredentialProvider>().As<ICredentialProvider>().SingleInstance();

                // Create the Bot Framework Adapter with error handling enabled.
                builder.RegisterType<AdapterWithErrorHandler>().As<IBotFrameworkHttpAdapter>().SingleInstance();

                // The Memory Storage used here is for local bot debugging only. When the bot
                // is restarted, everything stored in memory will be gone.
                IStorage dataStore = new MemoryStorage();

                // Create Conversation State object.
                // The Conversation State object is where we persist anything at the conversation-scope.
                var conversationState = new ConversationState(dataStore);
                builder.RegisterInstance(conversationState).As<ConversationState>().SingleInstance();

                // Register the main dialog, which is injected into the DialogBot class
                builder.RegisterType<RootDialog>().SingleInstance();

                // Register the DialogBot with RootDialog as the IBot interface
                builder.RegisterType<DialogBot<RootDialog>>().As<IBot>();

                var container = builder.Build();
                var resolver = new AutofacWebApiDependencyResolver(container);
                config.DependencyResolver = resolver;
            }

Solution

  • When a bot only works when it's running locally, memory storage is very often the issue. When a bot is deployed to an app service, there may be multiple instances of the service running simultaneously to provide high availability, and each instance will have its own memory. Like all REST API's, your bot needs to not rely on memory for the state it accesses across multiple turns. You need external storage so that all instances of the service have access to the same data, and so the data isn't lost when the service restarts. Please refer to the documentation for more information.