繁体   English   中英

Botframework v4:从子对话框调用父对话框,没有stackoverflow异常

[英]Botframework v4: Call parent dialog from child dialog without stackoverflow exception

根据这一点,我认为现在可以从子对话框中调用父对话框。 之前我不能这样做,因为它会导致堆栈溢出异常。 我已经更新到SDK 4.3有没有人知道如何实现这些更改?

主对话框调用对话框A.

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

  return await stepContext.BeginDialogAsync(DialogAId, cancellationToken: cancellationToken);

Dialog A调用Dialog Achild

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

   return await stepContext.BeginDialogAsync(DialogAchildId, cancellationToken: cancellationToken);

Dialog Achild调用MainDialog,但这会产生Stack溢出异常。

WaterfallStep[] waterfallSteps = new WaterfallStep[]
     {
        FirstStepAsync,
        SecondStepAsync,
        ThirdStepAsync,
     };
    AddDialog(new WaterfallDialog(InitialId, waterfallSteps));
    AddDialog(new MainDialog(MainDialogId));

  return await stepContext.BeginDialogAsync(MainDialogId, cancellationToken: cancellationToken);

假设您在对话框的构造函数中添加了Dialogs,那么您将产生一个无限循环,最终导致您正在描述的堆栈溢出。

MainDialog --> DialogA --> DialogAchild --> MainDialog --> infinite loop

你提到的PR指的是一个稍微不同的问题。

解决此问题的一种方法是删除AddDialog方法,从而导致构造函数的最终循环。 相反,将调用移动到AddDialogA()之类的方法,并仅在需要时调用它。

根据您的方案,您可以构建一个提供此类功能的基本对话框。

以下是AuthenticatedDialog的示例,您可以在必要时添加OnboardingDialog 请注意,Onboarding Dialog本身继承自AuthenticatedDialog,当您没有卸载AddDialog()调用时,它也会导致无限循环。

在基础对话框中对此进行抽象是很好的,因为它为您提供了一些可以使用的API。 考虑命名你的东西,如AddComponentDialog或UseComponentDialog。 通过这种方式,您表达了非常好的意图,并且潜在的读者最初知道您正在使用可重复使用的组件。

AuthenticatedDialog.cs

using Microsoft.Bot.Builder.Dialogs;
using Microsoft.Bot.Schema;
using Bot.Dialogs.Authentication;
using Bot.Dialogs.Main;
using Bot.Dialogs.Onboarding;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;

namespace Bot.Dialogs.Shared
{
    public class AuthenticatedDialog : EnterpriseDialog
    {
        private BotStateAccessors _accessors;
        private BotServices _botServices;

        public AuthenticatedDialog(BotServices botServices, string dialogId, BotStateAccessors accessors) : base(botServices, dialogId)
        {
            _accessors = accessors;
            _botServices = botServices;

            AddDialog(new AuthenticationDialog("", accessors));
        }

        protected async Task<DialogTurnResult> AskForOnboardingAsync(WaterfallStepContext stepContext, CancellationToken cancellationToken, object stepResult = null)
        {
            return await stepContext.BeginDialogAsync(nameof(OnboardingDialog), stepResult, cancellationToken);
        }

        protected void AddOnboardingDialog()
        {
            AddDialog(new OnboardingDialog(_botServices,_accessors));
        }

    }
}

DialogA.cs

public class DialogA : AuthenticatedDialog
{

        public DialogA(BotServices botServices, BotStateAccessors accessors) : base(botServices, nameof(DialogA), accessors)
        {

            var preferencesDispatchSteps = new WaterfallStep[]
            {
                WaterfallStepA,
                WaterfallStepB
            };

            AddDialog(new FooDialog);
            AddOnboardingDialog();
        }
}

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM