2

In my OnTurnAsync i am calling Main Dialog in a seperate class. And main dialog also calls other Dialog from other class and so on. Is this the right way to separate and extend Dialog? I each made separate Component Dialogs. Because i have a long flow of dialogs and doing them all in the Main Bot class is messy.

main dialog:

public class MainDialog : ComponentDialog
{
    private const string InitialId = "mainDialog";
    private const string ChoicePrompt = "choicePrompt";
    private const string DialogAId = "dialogAId";

    public MainDialog(string dialogId)
        : base(dialogId)
    {
        InitialDialogId = InitialId;

        WaterfallStep[] waterfallSteps = new WaterfallStep[]
         {
            FirstStepAsync,
            SecondStepAsync,
            ContinueStepAsync,
            ThirdStepAsync,
         };
        AddDialog(new WaterfallDialog(InitialId, waterfallSteps));
        AddDialog(new ChoicePrompt(ChoicePrompt));
        AddDialog(new DialogA(DialogAId));
    }

    private static async Task<DialogTurnResult> FirstStepAsync(WaterfallStepContext stepContext, CancellationToken cancellationToken = default(CancellationToken))
    {
        return await stepContext.PromptAsync(
            ChoicePrompt,
            new PromptOptions
            {
                Prompt = MessageFactory.Text($"Here are your choices:"),
                Choices = new List<Choice>
                    {
                        new Choice
                        {
                            Value = "Open Dialog A",
                        },
                        new Choice
                        {
                            Value = "Open Dialog B",
                        },
                    },
                RetryPrompt = MessageFactory.Text($"Please choose one of the options."),
            });
    }

    private static async Task<DialogTurnResult> SecondStepAsync(WaterfallStepContext stepContext, CancellationToken cancellationToken = default(CancellationToken))
    {
        var response = (stepContext.Result as FoundChoice)?.Value.ToLower();

        if (response == "open dialog a")
        {
            return await stepContext.BeginDialogAsync(DialogAId, cancellationToken: cancellationToken);
        }

        if (response == "open dialog b")
        {
            // re-prompt not working btw
            await stepContext.Context.SendActivityAsync(MessageFactory.Text($"Dialog B is not ready need to reprompt previous step."));
            await stepContext.RepromptDialogAsync();
        }

        return await stepContext.NextAsync();
    }

    private static async Task<DialogTurnResult> ThirdStepAsync(WaterfallStepContext stepContext, CancellationToken cancellationToken = default(CancellationToken))
    {
        // what is the best way to end this?
        // return await stepContext.ReplaceDialogAsync(InitialId);
        return await stepContext.EndDialogAsync();
    }
}

Dialog A code:

 public class DialogA : ComponentDialog
{
    private const string InitialId = "dialogA";
    private const string ChoicePrompt = "choicePrompt";
    private const string DialogAchildId = "dialogA_childId";

    public DialogA(string dialogId)
        : base(dialogId)
    {
        InitialDialogId = InitialId;

        WaterfallStep[] waterfallSteps = new WaterfallStep[]
         {
            FirstStepAsync,
            SecondStepAsync,
            ContinueStepAsync,
            ThirdStepAsync,
         };
        AddDialog(new WaterfallDialog(InitialId, waterfallSteps));
        AddDialog(new ChoicePrompt(ChoicePrompt));
        AddDialog(new DialogA_child(DialogAchildId));
    }

    private static async Task<DialogTurnResult> FirstStepAsync(WaterfallStepContext stepContext, CancellationToken cancellationToken = default(CancellationToken))
    {
        return await stepContext.PromptAsync(
            ChoicePrompt,
            new PromptOptions
            {
                Prompt = MessageFactory.Text($"Here are your choices:"),
                Choices = new List<Choice>
                    {
                        new Choice
                        {
                            Value = "Open Dialog A_Child",
                        },
                        new Choice
                        {
                            Value = "Open Dialog B_Child",
                        },
                    },
                RetryPrompt = MessageFactory.Text($"Please choose one of the options."),
            });
    }

    private static async Task<DialogTurnResult> SecondStepAsync(WaterfallStepContext stepContext, CancellationToken cancellationToken = default(CancellationToken))
    {
        var response = (stepContext.Result as FoundChoice)?.Value.ToLower();

        if (response == "open dialog a_child")
        {
            return await stepContext.BeginDialogAsync(DialogAchildId, cancellationToken: cancellationToken);
        }

        if (response == "open dialog b_child")
        {
            await stepContext.Context.SendActivityAsync(MessageFactory.Text($"Dialog B_child is not ready need to reprompt previous step."));
            await stepContext.RepromptDialogAsync();
        }

        return await stepContext.NextAsync();
    }

    private static async Task<DialogTurnResult> ContinueStepAsync(WaterfallStepContext stepContext, CancellationToken cancellationToken = default(CancellationToken))
    {
        await stepContext.Context.SendActivityAsync(MessageFactory.Text($"should continue when dialog Achild closed."));
        await stepContext.Context.SendActivityAsync(MessageFactory.Text($""));
        await stepContext.Context.SendActivityAsync(MessageFactory.Text($"will close dialog A."));
        return await stepContext.EndDialogAsync();
    }

    private static async Task<DialogTurnResult> ThirdStepAsync(WaterfallStepContext stepContext, CancellationToken cancellationToken = default(CancellationToken))
    {
        // what is the best way to end this?
        // return await stepContext.ReplaceDialogAsync(InitialId);
        return await stepContext.EndDialogAsync();
    }
user10860402
  • 754
  • 4
  • 22

1 Answers1

0

With the exception of the issue pointed out in your other issue, yes, you're going about complex dialog flow correctly.

It is far easier to manage a complex dialog flow by doing exactly what you're doing: having a main dialog class and then using if statements to branch into other dialogs. You may also want to consider using switch statements, especially if you might branch in more than two directions.

Good References

Advanced dialog flow - General guidelines

Creating reusable dialogs - General guidelines

What each method of stepContext does, in relation to dialogs - so you know what to call to accomplish what you want

Prompt Validation Sample - For integrating prompt validations, if necessary

mdrichardson
  • 6,656
  • 1
  • 3
  • 19
  • Thank you sir it is clear to me now. Could you also teach me about passing values? Right now i am just calling the accessors everytime and i feel like it is "hard coded". I see some samples like the one you gave me about `stepcontext.Options` and something like this `step.Values[GuestKey] = new GuestInfo();`. Do you mind teaching me about them? – user10860402 Feb 25 '19 at 20:47
  • This is my question about them. https://stackoverflow.com/questions/54799332/botframework-v4-stepcontext-option – user10860402 Feb 25 '19 at 20:50
  • I have submitted my answer for that one. – mdrichardson Feb 25 '19 at 22:04
  • Oh i did not notice he edited his answer. Thank you Mr. Richardson! – user10860402 Feb 26 '19 at 00:27
  • Mr. Richardson i made a short dialog chain but it is getting a stackoverflow exception. can you take a look? https://stackoverflow.com/questions/54885861/stackoverflow-exception-in-a-simple-dialog-in-botframework-v4 – user10860402 Feb 26 '19 at 12:43
  • It is because it has many upvotes. But i did not understand it so much and not solve my problem. – user10860402 Feb 26 '19 at 21:06
  • I thought so. I'll have an answer up there shortly. – mdrichardson Feb 26 '19 at 21:07
  • Thank you so much sir Mr.richardson. I will be able to check it later about after 2 hours. – user10860402 Feb 26 '19 at 21:09