如何使用状态访问器获取 Bot Framework 中的属性
How to use State Accessors to get properties in Bot Framework
我的机器人的功能之一是处理购物车。用户可以在对话中的任意位置添加项目,然后完成购物以关闭产品购物车。
为了避免将购物车从一个对话框传递到另一个对话框,我想在 UserState
中创建一个 UserProfile
属性(UserProfile
属性 有ShoppingCart
属性)但我不太清楚如何正确使用它。
我的主对话框包含一组子对话框,其中一些需要能够访问 ShoppingCart
对象。我在示例中找到了一些示例,但其中 none 实现了我想要实现的目标。在状态管理示例中:
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;
}
}
如果我没理解错的话,每次他想要获取访问器时都会创建一个新的属性?或者一旦创建了 属性 如果您调用 CreateProperty
没有 属性 将被创建并返回访问器?
我考虑过在 Bot 上获取访问器,然后将其传递给 MainDialog
,然后传递给 ChildDialogs
,但这有点违背了不通过对话框传递 ShoppingCart
的目的.
我不能每次都创建一个 属性 来获取访问器吗?
我读过this issue,它给出了我的问题的解决方案,但后来我看到@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.
如果我想在我的对话框中获取 ShoppingCart
(在我需要访问的 UserProfile
属性 中),我应该什么时候创建访问器?
快速回答:
您应该在所有需要操作状态的对话框中创建访问器。
详细答案:
CreateProperty 不会实际创建 属性,它只是:
Creates a property definition and register it with this BotState
CreateProperty() 会 return 你一个 BotStatePropertyAccessor 你可以调用 GetAsync、SetAsync 和 DeleteAsync 它们将从轮流上下文中的状态缓存中获取、设置和删除 属性。(内部缓存机器人状态)
当您调用 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() 先到:
Reads in the current state object and caches it in the context
object for this turn.
并且当调用GetAsync()并且没有找到key时,它会自动调用SetAsync 设置新的 属性
如果您正在使用 AutoSaveStateMiddleware,该中间件将:
automatically call .SaveChanges() at the end of the turn for all
BotState class it is managing.
我的机器人的功能之一是处理购物车。用户可以在对话中的任意位置添加项目,然后完成购物以关闭产品购物车。
为了避免将购物车从一个对话框传递到另一个对话框,我想在 UserState
中创建一个 UserProfile
属性(UserProfile
属性 有ShoppingCart
属性)但我不太清楚如何正确使用它。
我的主对话框包含一组子对话框,其中一些需要能够访问 ShoppingCart
对象。我在示例中找到了一些示例,但其中 none 实现了我想要实现的目标。在状态管理示例中:
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;
}
}
如果我没理解错的话,每次他想要获取访问器时都会创建一个新的属性?或者一旦创建了 属性 如果您调用 CreateProperty
没有 属性 将被创建并返回访问器?
我考虑过在 Bot 上获取访问器,然后将其传递给 MainDialog
,然后传递给 ChildDialogs
,但这有点违背了不通过对话框传递 ShoppingCart
的目的.
我不能每次都创建一个 属性 来获取访问器吗?
我读过this issue,它给出了我的问题的解决方案,但后来我看到@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.
如果我想在我的对话框中获取 ShoppingCart
(在我需要访问的 UserProfile
属性 中),我应该什么时候创建访问器?
快速回答: 您应该在所有需要操作状态的对话框中创建访问器。
详细答案:
CreateProperty 不会实际创建 属性,它只是:
Creates a property definition and register it with this BotState
CreateProperty() 会 return 你一个 BotStatePropertyAccessor 你可以调用 GetAsync、SetAsync 和 DeleteAsync 它们将从轮流上下文中的状态缓存中获取、设置和删除 属性。(内部缓存机器人状态)
当您调用 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() 先到:
Reads in the current state object and caches it in the context object for this turn.
并且当调用GetAsync()并且没有找到key时,它会自动调用SetAsync 设置新的 属性
如果您正在使用 AutoSaveStateMiddleware,该中间件将:
automatically call .SaveChanges() at the end of the turn for all BotState class it is managing.