[英]How to use State Accessors to get properties in 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.
用户可以在对话中的任何位置添加商品,然后完成购物以关闭产品购物车。
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.为避免将购物车从对话框传递到对话框,我想在
UserState
中创建一个UserProfile
属性( UserProfile
属性具有ShoppingCart
属性),但我不太清楚如何正确使用它。
My Main Dialog contains a set of Child Dialogs and some of them need to be able to access the ShoppingCart
object.我的主对话框包含一组子对话框,其中一些需要能够访问
ShoppingCart
object。 I found some examples in the samples but none of them do what I want to achieve.我在示例中找到了一些示例,但它们都没有达到我想要的效果。 In the State Management sample:
在 State 管理示例中:
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;
}
}
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?或者,如果您调用
CreateProperty
创建了一个属性,则不会创建任何属性并返回访问器?
I thought about getting the accessor on the Bot and then passing it to MainDialog
and then to the ChildDialogs
but it kinda defeats the purpose of not passing the ShoppingCart
through Dialogs.我曾想过在 Bot 上获取访问器,然后将其传递给
MainDialog
,然后ChildDialogs
,但这有点违背了不通过对话框传递ShoppingCart
的目的。
Can't I get the accessors without having to create a Property every time?我不能在不必每次都创建属性的情况下获取访问器吗?
I've readthis issue which gives a solution to my problem, but then I saw @johnataylor 's comment saying我读过这个问题,它可以解决我的问题,但后来我看到@johnataylor的评论说
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.
我们遵循的模式是将访问器的创建推迟到我们需要它时——这似乎最有效地隐藏了固有的噪音。
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?如果我想在我的对话框中获取
ShoppingCart
(位于我需要访问的UserProfile
属性内),我应该何时创建访问器?
Fast Answer: You should create the accessor in the all the dialogs where you need to manipulate the state.快速回答:您应该在需要操作 state 的所有对话框中创建访问器。
Detailed Answer:详细答案:
CreateProperty does not physically create the property, it just: CreateProperty不会物理地创建属性,它只是:
Creates a property definition and register it with this BotState
创建一个属性定义并将其注册到此 BotState
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) CreateProperty()将返回一个BotStatePropertyAccessor ,您可以从中调用GetAsync 、 SetAsync和DeleteAsync ,它们将从转弯上下文中的 state 缓存中获取、设置和删除属性。(内部缓存机器人状态)
When you call BotState.SaveChangesAsync() this will:当您调用BotState.SaveChangesAsync()这将:
If it has changed, writes to storage the state object that is cached in the current context object for this turn.
如果它已更改,则将在当前上下文 object 中缓存的 state object 写入存储。
Each call of GetAsync , SetAsync will actually call BotState.LoadAsync() first to:每次调用GetAsync , SetAsync实际上都会首先调用BotState.LoadAsync()来:
Reads in the current state object and caches it in the context object for this turn.
读取当前的 state object 并将其缓存在上下文 object 中以供本回合使用。
And when GetAsync() is called and no key is found , it will automatically call SetAsync to set that new property并且当调用 GetAsync()并且没有找到键时,它将自动调用SetAsync来设置该新属性
If you are using AutoSaveStateMiddleware that middleware will:如果您使用的是AutoSaveStateMiddleware ,该中间件将:
automatically call.SaveChanges() at the end of the turn for all BotState class it is managing.
在回合结束时自动为它管理的所有 BotState class 调用.SaveChanges()。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.