1

First I've to take phone no as a user input, than I need to call qnadialog till user quits. Following is my code:

public class RootDialog : IDialog<object>
{
    private string phoneNo;
    public async Task StartAsync(IDialogContext context)
    {
        context.Wait(this.MessageReceivedAsync);
    }

    private async Task MessageReceivedAsync(IDialogContext context, IAwaitable<object> result)
    {
        var activity = await result;

        await this.SendWelcomeMessageAsync(context);
    }
    private async Task SendWelcomeMessageAsync(IDialogContext context)
    {
        if (string.IsNullOrEmpty(phoneNo))
        {
            await context.PostAsync("Hi, I'm Anna. Let's get started.");
            context.Call(new PhoneNoDialog(), this.PhoneNoDialogResumeAfter);
        }
        else
        {
            await context.Forward(new SimpleQnADialog(), ResumeAfterSimpleQnADialog, context.Activity, CancellationToken.None);                
        }
    }
    private async Task PhoneNoDialogResumeAfter(IDialogContext context, IAwaitable<string> result)
    {
            this.phoneNo = await result;
            await context.PostAsync($"Thank you for the information. How can I help you?");
            context.Wait(this.MessageReceivedAsync);
    }

    private async Task ResumeAfterSimpleQnADialog(IDialogContext context, IAwaitable<object> result)
    {
            context.Done<object>(null);            
    }
}

PhoneNoDialog.cs

public class PhoneNoDialog : IDialog<string>
{
    private int attempts = 3;

    public async Task StartAsync(IDialogContext context)
    {
        await context.PostAsync("Please enter your phone no");

        context.Wait(this.MessageReceivedAsync);
    }

    private async Task MessageReceivedAsync(IDialogContext context, IAwaitable<IMessageActivity> result)
    {
        var message = await result;

        if ((message.Text != null) && (message.Text.Trim().Length > 0))
        {
            context.Done(message.Text);
        }
        else
        {
            --attempts;
            if (attempts > 0)
            {
                await context.PostAsync("I'm sorry, I don't understand your reply. What is your phone no?");
                context.Wait(this.MessageReceivedAsync);
            }
            else
            {
                context.Fail(new TooManyAttemptsException("Message was not a string or was an empty string."));
            }
        }
    }
}

SimpleQnADialog.cs

[QnAMaker("subkey", "kbid")]
public class SimpleQnADialog : QnAMakerDialog
{

}

Everything works fine if I create independent bot with QnAmaker but if I call the context in above mentioned way, than it doesn't work as expected. I am not sure where I'm going wrong with this. And also, many a times bot emulator gives unexpected exceptions.

Sahil Tyagi
  • 147
  • 2
  • 5
  • I try to reproduce the issue based on the code you provided, it works on my side. Please check if it forwards to your `SimpleQnADialog` and if it makes request to your QnA Maker service? – Fei Han Mar 15 '18 at 05:48
  • Can you add a demo (capture of emulator?) of the issue? – Nicolas R Mar 15 '18 at 10:20
  • @NicolasR :Please go through the trail log from bot emulator for one such errors that I get arbitrarily: [19:35:19] <- POST 200 setPrivateConversationData [19:35:20] <- POST 200 setConversationData [19:35:20] <- POST 200 setUserData [19:35:21] -> POST 200 [message] how to check status? [19:35:31] -> POST 500 [message] what not to do? [19:35:44] -> POST 500 [message] how to get things done? [19:35:56] -> POST 500 [message] hello POST 500 messages are all errors. And it sometimes throws exceptions like "Empty stack" or "An error occured while sending the request" – Sahil Tyagi Mar 15 '18 at 14:10

1 Answers1

1

You are trying to complete your RootDialog after the QnA got a reply when you implement this:

private async Task ResumeAfterSimpleQnADialog(IDialogContext context, IAwaitable<object> result)
{
        context.Done<object>(null);            
}

In fact, the QnAMakerDialog is completing once it has tried to answer, as you can see on its sources here.

If you want to loop on questions, you should call again the wait:

private async Task ResumeAfterSimpleQnADialog(IDialogContext context, IAwaitable<object> result)
{
    context.Wait(this.MessageReceivedAsync);
}
Nicolas R
  • 13,812
  • 2
  • 28
  • 57