Botframework V4:即使其他对话框处于活动状态,活动对话框的ID也不会更改

时间:2019-04-09 13:25:26

标签: c# botframework

我需要根据活动对话框的ID来做一个条件。

var dc = await _dialogs.CreateContextAsync(turnContext);
if (dc.ActiveDialog != null && dc.ActiveDialog.id == "SkipLuisDialog")
{
    var interruptedQnaMaker = await IsTurnInterruptedDispatchToQnAMakerAsync(turnContext, topDispatch, QnaConfiguration, cancellationToken);
}

当我像这样检查OnTurnAsync()上的活动对话框时:

            if (dc.ActiveDialog != null)
            {
                await dc.Context.SendActivityAsync(dc.ActiveDialog.Id.ToString());
            }   

它总是说“ mainDialog”,这是我的主对话框的ID。即使在“ FAQDialog”或“ complaintDialog”上输入即时消息,活动对话框的ID也始终为“ mainDialog”。为什么在FAQ对话框中的im时活动对话框ID不会更改为“ FAQDialog”,而在投诉对话框中的im则为什么活动对话框ID不会更改为“ complaintDialog”?

我的主对话框和其他对话框在另一个类中。 这就是我在OnTurnAsync()上调用mainDialog的方式:

  if (!dc.Context.Responded)
            {
                switch (dialogResult.Status)
                {
                    case DialogTurnStatus.Empty:

                        switch (topIntent) // topIntent // text
                        {
                            case GetStartedIntent:
                                await dc.BeginDialogAsync(MainDialogId);
                                break;                          

                            case NoneIntent: 
                            default:
                                await dc.Context.SendActivityAsync("I didn't understand what you just said to me.");
                                break;
                        }

                        break;

                    case DialogTurnStatus.Waiting:
                        // The active dialog is waiting for a response from the user, so do nothing.
                        break;

                    case DialogTurnStatus.Complete:
                        await dc.EndDialogAsync();
                        break;

                    default:
                        await dc.CancelAllDialogsAsync();
                        break;
                }
            }

主对话框:

namespace CoreBot.Dialogs

{     公共类MainDialog:ComponentDialog     {         私有常量字符串InitialId =“ mainDialog”;         私有常量字符串TextPromptId =“ textPrompt”;

    private const string ComplaintDialogId = "complaintDialog";
    private const string FAQDialogId = "FAQDialog";

    public MainDialog(string dialogId) : base(dialogId)
    {
        WaterfallStep[] waterfallSteps = new WaterfallStep[]
        {
            FirstStepAsync,
            SecondStepAsync,
            ThirdStepAsync,

        };
        AddDialog(new WaterfallDialog(InitialId, waterfallSteps));
        AddDialog(new FAQDialog(FAQDialogId));
        AddDialog(new FileComplaintDialog(ComplaintDialogId));
        AddDialog(new TextPrompt(TextPromptId));
    }

    private static async Task<DialogTurnResult> FirstStepAsync(WaterfallStepContext stepContext, CancellationToken cancellationToken = default(CancellationToken))
    {
        return await stepContext.PromptAsync(
            TextPromptId,
            new PromptOptions
            {
                Prompt = new Activity
                {
                    Type = ActivityTypes.Message,
                    Text = $"What can i do for you?",
                    SuggestedActions = new SuggestedActions()
                    {
                        Actions = new List<CardAction>()
                        {
                                new CardAction() { Title = "Frequently Asked Questions", Type = ActionTypes.ImBack, Value = "Frequently Asked Questions" },
                                new CardAction() { Title = "File a Complaint Ticket", Type = ActionTypes.ImBack, Value = "File a Complaint Ticket" },
                        },
                    },
                },
            });
    }

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

        string[] FAQArray = { "frequently asked questions", "question", "ask question" };
        string[] ComplaintsArray = { "file a complaint ticket", "complaint", "file a complaint" };

        if (FAQArray.Contains(response))
        {
            return await stepContext.BeginDialogAsync(FAQDialogId, cancellationToken);
        }

        if (ComplaintsArray.Contains(response))
        {
            await stepContext.EndDialogAsync();
            return await stepContext.BeginDialogAsync(ComplaintDialogId, cancellationToken: cancellationToken);
        }

        return await stepContext.NextAsync();
    }

    private static async Task<DialogTurnResult> ThirdStepAsync(WaterfallStepContext stepContext, CancellationToken cancellationToken = default(CancellationToken))
    {
        return await stepContext.ReplaceDialogAsync(InitialId);
    }

}

}

主对话框调用2个对话框。这就是其中之一。

    namespace CoreBot.Dialogs
{
    public class FAQDialog : ComponentDialog
    {
        private const string InitialId = "FAQDialog";
        private const string ChoicePromptId = "choicePrompt";
        private const string TextPromptId = "textPrompt";
        private const string ConfirmPromptId = "confirmPrompt";

        public FAQDialog(string dialogId) : base(dialogId)
        {
            WaterfallStep[] waterfallSteps = new WaterfallStep[]
            {
                FirstStepAsync,
                SecondStepAsync,
                ThirdStepAsync,
                FourthStepAsync,
            };
            AddDialog(new WaterfallDialog(InitialId, waterfallSteps));
            AddDialog(new ChoicePrompt(ChoicePromptId));
            AddDialog(new ConfirmPrompt(ConfirmPromptId));
            AddDialog(new TextPrompt(TextPromptId));

        }
        private static async Task<DialogTurnResult> FirstStepAsync(WaterfallStepContext stepContext, CancellationToken cancellationToken = default(CancellationToken))
        {
            var choices = new List<Choice>();
            choices.Add(new Choice { Value = "This is Sample Question 1", Synonyms = new List<string> { "Question 1" } });
            choices.Add(new Choice { Value = "This is Sample Question 2", Synonyms = new List<string> { "Question 2" } });

            return await stepContext.PromptAsync(
                ChoicePromptId,
                new PromptOptions
                {
                    Prompt = MessageFactory.Text($"Welcome to FAQ! Choose the number of the question or type your own question."),
                    Choices = choices,
                });
        }

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


            switch (choiceResult)
            {
                case "this is sample question 1":
                    await stepContext.Context.SendActivityAsync(MessageFactory.Text($"Answer to question 1."));
                    break;

                case "this is sample question 2":
                    await stepContext.Context.SendActivityAsync(MessageFactory.Text($"Answer to question 2."));
                    break;

                default:
                    break;
            }

            return await stepContext.NextAsync();
        }

        private static async Task<DialogTurnResult> ThirdStepAsync(WaterfallStepContext stepContext, CancellationToken cancellationToken = default(CancellationToken))
        {
            return await stepContext.PromptAsync(
                ConfirmPromptId,
                new PromptOptions
                {
                    Prompt = MessageFactory.Text($"Have another question?"),
                });

        }

        private static async Task<DialogTurnResult> FourthStepAsync(WaterfallStepContext stepContext, CancellationToken cancellationToken = default(CancellationToken))
        {
            var confirmResult = (bool)stepContext.Result;

            if (confirmResult)
            {
                await stepContext.Context.SendActivityAsync(MessageFactory.Text($"Ask away!"));
                return await stepContext.ReplaceDialogAsync(InitialId);
            }
            else
            {
                await stepContext.Context.SendActivityAsync(MessageFactory.Text($"Great!"));
                return await stepContext.EndDialogAsync();
            }
        }

    }
}

1 个答案:

答案 0 :(得分:1)

这是因为在MainDialog中调用了所有对话框。

Dialog Stack Concept

这里或多或少是怎么回事:

MyBot.cs(或您的主.cs主文件中)中,您有类似Dialogs = new DialogSet(_dialogStateAccessor)的内容,它将创建一个空对话框stack

 ___________

然后,您使用类似await dc.BeginDialogAsync(MainDialogId);的名称,它将MainDialog添加到对话框堆栈的顶部:

 ______________
|  MainDialog  |
|______________|

如果您在MainDialog外部调用return await stepContext.BeginDialogAsync(FAQDialogId, cancellationToken);,则堆栈将如下所示:

 ______________
|  FAQDialogId |
|______________|
 ______________
|  MainDialog  |
|______________|

但是,您是从MainDialog内部调用return await stepContext.BeginDialogAsync(FAQDialogId, cancellationToken);的,因此它是自己的堆栈,因此FAQDialog是MainDialog中的活动对话框,但是您的Dialogs堆栈仍将MainDialog作为ActiveDialog。因此,您的堆栈或多或少是这样的:

 _______________________
| ______________        |
| |__FAQDialog__|       |
|                       |
|            MainDialog |
|_______________________|

做自己想做的事

您有两种选择:

1。从MainDialog外部调用所有其他对话框。

如果您不打算返回MainDialog,则可以执行以下操作:

MainDialog中:

return await stepContext.EndDialogAsync("FAQDialog");

MyBot.cs中:

switch (dialogResult)
{
    case "FAQDialog":
        dc.BeginDialogAsync(FAQDialogId, cancellationToken);
        break;
    case "ComplaintDialog":
        dc.BeginDialogAsync(ComplaintDialogId, cancellationToken);
        break;
}

2。在ActiveDialog堆栈中挖出对话框的ID

if (dc.ActiveDialog != null && IsDialogInStack(dc.ActiveDialog, "SkipLuisDialog"))
{
    var interruptedQnaMaker = await IsTurnInterruptedDispatchToQnAMakerAsync(turnContext, topDispatch, QnaConfiguration, cancellationToken);
}

[...]

private bool IsDialogInStack(DialogInstance activeDialog, string searchId)
{
    if (activeDialog.Id == searchId)
    {
        return true;
    };
    foreach (KeyValuePair<string, object> item in activeDialog.State)
    {
        if (item.Key == "dialogs" && item.Value is DialogState)
        {
            DialogState dialogState = (DialogState)item.Value;
            foreach (DialogInstance dialog in dialogState.DialogStack)
            {
                return IsDialogInStack(dialog, searchId);
            }
        }
    }
    return false;
}

注意:我不是C#专家,也许可以使用更好的方法来编写IsDialogInStack,但是上面的代码可以正常工作。