如何使用状态访问器获取Bot Framework中的属性

时间:2019-10-11 10:04:35

标签: c# asp.net-core botframework accessor

我的机器人的功能之一是处理购物车。用户可以在对话中的任何地方添加商品,然后完成购物以关闭商品购物车。

为了避免将购物车从对话框传递到对话框,我想在UserProfile中创建一个UserState属性(UserProfile属性具有ShoppingCart属性),但是我不太了解如何正确使用它。

“我的主对话框”包含一组子对话框,其中一些必须能够访问ShoppingCart对象。我在示例中找到了一些示例,但是它们都没有达到我想要的目标。在“状态管理”样本中:

protected override async Task OnMessageActivityAsync(ITurnContext<IMessageActivity> turnContext, CancellationToken cancellationToken)
        {
            // Get the state properties from the turn context.

            var conversationStateAccessors =  _conversationState.CreateProperty<ConversationData>(nameof(ConversationData));
            var conversationData = await conversationStateAccessors.GetAsync(turnContext, () => new ConversationData());

            var userStateAccessors = _userState.CreateProperty<UserProfile>(nameof(UserProfile));
            var userProfile = await userStateAccessors.GetAsync(turnContext, () => new UserProfile());

            if (string.IsNullOrEmpty(userProfile.Name))
            {
                // First time around this is set to false, so we will prompt user for name.
                if (conversationData.PromptedUserForName)
                {   
                    // Set the name to what the user provided.
                    userProfile.Name = turnContext.Activity.Text?.Trim();

                    // Acknowledge that we got their name.
                    await turnContext.SendActivityAsync($"Thanks {userProfile.Name}. To see conversation data, type anything.");

                    // Reset the flag to allow the bot to go though the cycle again.
                    conversationData.PromptedUserForName = false;
                }
                else
                {
                    // Prompt the user for their name.
                    await turnContext.SendActivityAsync($"What is your name?");

                    // Set the flag to true, so we don't prompt in the next turn.
                    conversationData.PromptedUserForName = true;
                }
            }

如果我理解正确,那么他每次想要获取访问器时都会创建一个新的Property吗?还是一旦创建属性(如果您调用CreateProperty,就不会创建任何属性并返回访问器?

我考虑过将访问器放在Bot上,然后将其传递给MainDialog,然后传递给ChildDialogs,但这有点违反了不通过对话框传递ShoppingCart的目的。 / p>

是否不必每次都创建属性就可以获取访问器?

我已经读过this issue,该书为我的问题提供了解决方案,但是后来我看到 @johnataylor 的评论说

  

我们遵循的模式是将访问器的创建推迟到我们需要它之前-这似乎最有效地隐藏了固有的噪声。

如果我想在对话框中获取ShoppingCart(位于我需要访问的UserProfile属性内),应该何时创建访问器?

1 个答案:

答案 0 :(得分:1)

快速答案: 您应该在需要操纵状态的所有对话框中创建访问器。

详细答案:

CreateProperty 并不实际创建属性,而只是创建:

  

创建一个属性定义并将其注册到此BotState

CreateProperty()将为您返回一个 BotStatePropertyAccessor ,您可以从中调用 GetAsync SetAsync DeleteAsync ,它们将在转弯上下文中从状态缓存中获取,设置和删除属性。(内部缓存的漫游器状态)

调用 BotState.SaveChangesAsync()时,这将:

  

如果已更改,则将本次缓存在当前上下文对象中的状态对象写入存储。

每次 GetAsync SetAsync 的调用实际上都会首先调用 BotState.LoadAsync()

  

读取当前状态对象并将其缓存在上下文中   此回合的对象。

并且当调用 GetAsync()未找到键时,它将自动调用 SetAsync 来设置该新属性

如果您使用的是 AutoSaveStateMiddleware ,则该中间件将:

  

在回合结束时自动为所有人调用.SaveChanges()   它正在管理的BotState类。