【问题标题】:Using Bot State Accessors Inside Dialogs在对话框中使用 Bot 状态访问器
【发布时间】:2019-07-25 07:13:46
【问题描述】:

我在 Bot Framework 上已经有几天时间了,非常新。我一直在努力理解管理状态,老实说,我只是不明白。看来这方面的框架和建议最近发生了很大变化,似乎没有任何明确的建议或示例。

这个page 说:

将信息保存到机器人状态。这将需要您设计 您的对话框可以访问机器人的状态属性访问器。

但是没有关于如何实现这一点的示例。

我的一个瀑布对话框中的最后一步如下所示:

AddStep(async (stepContext, cancellationToken) =>
{
    var response = stepContext.Result as FoundChoice;
    stepContext.Values["maxPrice"] = response;

    return await stepContext.BeginDialogAsync(SearchDialog.Id, null, cancellationToken);
});

它基本上是在启动一个新对话框,我想通过传递对象将收集到的数据从该对话框传递到SearchDialog,或者最好将其保存到我的BotAccessors 然后SearchDialog 检索这个和使用它。

所有 MS 示例都有瀑布步骤,定义为 IBot 类上的 async 方法。这也不是他们建议将机器人对话框放在一起的方式,这使得该示例总体上毫无用处。

此外,似乎即使是 Microsoft v4 文档也已过时,例如 this doc,它仍在告诉我们使用已弃用的代码,例如:

options.State.Add(new ConversationState(storage));

不幸的是,目前这些文档似乎更令人困惑而不是对这个主题有帮助。管理这种状态的最佳方法是什么?

【问题讨论】:

  • 您还需要帮助吗?
  • 我还没有开始研究这个。到目前为止,似乎默认的内置对话框根本没有考虑到 DI,这是不幸的。此外,在使用之前构建对话集的方式也使 DI 存在问题。一旦我有更多时间研究它,我会用 A 更新这个 Q。

标签: c# botframework


【解决方案1】:

注意:Basic Bot 示例已被 Core Bot 示例替换,因此此答案已过时

看看在samples repocreating a basic bot 从Azure 模板中设置基本机器人的方式。

状态属性访问器在BasicBot 类中声明:

private readonly IStatePropertyAccessor<GreetingState> _greetingStateAccessor;

然后分配到BasicBotconstructor:

_greetingStateAccessor = _userState.CreateProperty<GreetingState>(nameof(GreetingState));

然后是passedGreetingDialog 构造函数:

Dialogs.Add(new GreetingDialog(_greetingStateAccessor, loggerFactory));

然后将其分配给GreetingDialog 类的属性:

UserProfileAccessor = userProfileStateAccessor ?? throw new ArgumentNullException(nameof(userProfileStateAccessor));

然后在GreetingDialog 类的许多地方使用GetAsyncSetAsync 方法。例如:

var greetingState = await UserProfileAccessor.GetAsync(stepContext.Context, () => null);

【讨论】:

  • 当然这都是标准的法耶,但真的,真的不会导致我认为是好的做法或依赖注入。 IoC a lá Mvvm 是我用于许多类型项目的一种方法。用对话框来做这件事似乎很尴尬。
  • 像这样手动传递东西是一件坏事。特别是在 .NET 核心应用程序中,DI 和 IoC 最终成为一等公民。
  • 也就是说,这篇文章是一个很好的例子,我已经在做。
  • 谢谢。您想向 GitHub 存储库提交设计建议吗?
  • 你认为这个 Stack Overflow 问题已经解决了吗?
【解决方案2】:

瀑布对话框的最后两个步骤可能如下所示:

public async Task<DialogTurnResult> AskForLocation(WaterfallStepContext sc, CancellationToken cancellationToken)
    {
        // the previous step asked for the Email so now bot is going to save it in botstate
        _state = await _accessor.GetAsync(sc.Context, () => new MyApplicationState());
        var email = _state.Email = (string)sc.Result;

        // this is not in the template because it is saving in a different manner
        // just being explicit about saving here
        await _accessor.SetAsync(sc.Context, _state);

        await sc.Context.SendActivityAsync("Got your email!");

        var prompt = new PromptOptions
        {
                Prompt = MessageFactory.Text($"Please specify location."),
        };

        return await stepContext.PromptAsync(locationPrompt, prompt);
    }

    public async Task<DialogTurnResult> FinishDialog(WaterfallStepContext sc, CancellationToken cancellationToken)
    {
        _state = await _accessor.GetAsync(sc.Context);
        _state.Location = (string)sc.Result;

        // save location this time
        await _accessor.SetAsync(sc.Context, _state);

        await sc.Context.SendActivityAsync("Got your location!");

        return await sc.EndDialogAsync();
    }

如果您退出了上面的对话框,并假设您实现了 StateBotAccessors 并且正在使用 UserProfile 属性,那么您可以通过以下方式检索它:

    var _state = await stateBotAccessors.UserState.UserProfileAccessor.GetAsync(context);

或者,如果您想从子对话框中传递它,您可以以以下方式结束:

    return await sc.EndDialogAsync(_state);

【讨论】:

  • 实际上,我的问题更多是关于如何让 BotAccessor 进入对话框。在 BotFramework 中使用 DI 似乎很尴尬。
  • docs.microsoft.com/en-us/azure/bot-service/… 中查看“配置你的机器人”,它解决了如何在 Startup.cs 中进行设置。这就是你要找的东西吗?
  • DI 代表什么?
  • 我认为他的意思是依赖注入
  • 确实我的意思是 DI。
猜你喜欢
  • 2019-10-16
  • 1970-01-01
  • 2021-03-11
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-02-15
相关资源
最近更新 更多