frameworksbotsazure-language-understandingmbf

Quit current dialog if user wants to stop


I am using multiple dialogs. Some use formbuilder, some use a ResultAfter method for custom prompting of values. I want a method to check incomming messages on exit words like stop, quit etc.

I thought the StartAsync function would be a good start. Seeing all dialogs are forwarded from my RootDialog I have implemented this in the RootDialog:

    public override async Task StartAsync(IDialogContext context)
    {
        string[] stopStrings = { "quit", "cancel", "exit" };
        var msg = context.Activity.AsMessageActivity().Text;
        if (stopStrings.Any(msg.Contains))
        {
            await context.PostAsync("You cancelled.");
            context.Done(true);
        }
        else
        {
            context.Wait(this.MessageReceived);
        }
    }

When I ask the bot to "stop" it succesfully tells me I cancelled. But on the next message I send I get this error:

Exception thrown: 'System.Collections.Generic.KeyNotFoundException'

At this line in my MessageController:

await Conversation.SendAsync(activity, () => new RootDialog());

Now I am not sure what key is not found, and why it sends me this. Help is appreciated!


Solution

  • Generally, when someone wants to accomplish something like this such as a keyword to cancel they use scorables. Scorables are global message handlers so if a keyword you set triggers one it gets handled before firing off your normal dialog flow. There are some great resources out there for scorables like this blog or this video should get you started.

    I wasn't actually able to reproduce this error, but here are some tips and thoughts. I don't think I have ever seen someone put logic in StartAsync and act as they would expect it to. I wasn't able to figure out why you are overriding it the way you are when i was trying your code. The logic should be in MessageReceivedAsync. Try moving your logic into the MessageReceivedAsync method. Another thing to try if you absolutely want to do it this way it to replace context.Done(true) with just context.Wait(this.MessageReceivedAsync); since you are in the RootDialog anyways, messages will just be routed there from the messages controller and you do not need to manually manipulate the dialog stack, although I do not know the structure of your project so I could be wrong.