如何使用状态访问器获取Bot Framework中的属性 [英] How to use State Accessors to get properties in Bot Framework

查看:91
本文介绍了如何使用状态访问器获取Bot Framework中的属性的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

One of the functionalities of my bot is handling a Shopping Cart. The user can add items anywhere in the conversation and then finish shopping to close the product cart.

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

To avoid passing the cart from dialog to dialog I would like to create a UserProfile property in the UserState (The UserProfile property has a ShoppingCart attribute) but I don't quite know how to use this properly.

我的主对话框"包含一组子对话框,其中一些子对话框需要能够访问ShoppingCart对象.我在示例中找到了一些示例,但没有一个示例可以达到我想要的目的.在状态管理"样本中:

My Main Dialog contains a set of Child Dialogs and some of them need to be able to access the ShoppingCart object. I found some examples in the samples but none of them do what I want to achieve. In the State Management sample:

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),将不会创建任何属性并返回访问器?

If I understand correctly, every time he wants to get the accessor a new Property is created? Or once a property is created if you call CreateProperty no property will be creater and the accessor is returned?

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

I thought about getting the accessor on the Bot and then passing it to MainDialogand then to the ChildDialogs but it kinda defeats the purpose of not passing the ShoppingCartthrough Dialogs.

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

Can't I get the accessors without having to create a Property every time?

我已阅读此问题解决我的问题的方法,但后来我看到 @johnataylor 的评论说

I've read this issue which gives a solution to my problem, but then I saw @johnataylor's comment saying

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

The pattern we follow is to defer the creation of the accessor until we need it - this seems to hide the inherent noise the most effectively.

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

When should I create the accessors if I want to get the ShoppingCart (which is inside the UserProfile property that I need to access) inside my Dialogs?

推荐答案

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

详细答案:

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

CreateProperty does not physically create the property, it just:

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

Creates a property definition and register it with this BotState

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

CreateProperty() will return you a BotStatePropertyAccessor from which you can call GetAsync,SetAsync and DeleteAsync those will Get, Set and delete a property from the state cache in the turn context.(Internal cached bot state)

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

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

If it has changed, writes to storage the state object that is cached in the current context object for this turn.

每次调用 GetAsync SetAsync 时,实际上都会先调用 BotState.LoadAsync():

Each call of GetAsync,SetAsync will actually call BotState.LoadAsync() first to:

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

Reads in the current state object and caches it in the context object for this turn.

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

And when GetAsync() is called and no key is found, it will automatically call SetAsync to set that new property

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

If you are using AutoSaveStateMiddleware that middleware will:

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

automatically call .SaveChanges() at the end of the turn for all BotState class it is managing.

这篇关于如何使用状态访问器获取Bot Framework中的属性的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆