首页 > 解决方案 > 从 DialogContext 获取 TurnState 数据

问题描述

我正在使用 BotBuilder SDK v4。这是下面的解释(忽略一些额外的代码)。

在我的机器人上OnTurnAsync,我正在像这样调用我的一个对话框。

public async Task OnTurnAsync(ITurnContext turnContext, CancellationToken cancellationToken = default(CancellationToken))
{
    var state = await _accessors.TurnStateAccessor.GetAsync(turnContext, () => new TurnState()).ConfigureAwait(false);
    var dialogContext = await _dialogs.CreateContextAsync(turnContext).ConfigureAwait(false);       
    await dialogContext.BeginDialogAsync(nameof(SomeDialog)).ConfigureAwait(false);

    //remaining code..
}

调用成功并到达对话框。下面是代码。

public override Task<DialogTurnResult> BeginDialogAsync(DialogContext outerDc, object options = null, CancellationToken cancellationToken = default(CancellationToken))
{
    outerDc.ContinueDialogAsync();
    return base.BeginDialogAsync(outerDc, options, cancellationToken);
}

public override Task<DialogTurnResult> ContinueDialogAsync(DialogContext outerDc, CancellationToken cancellationToken = default(CancellationToken))
{
    var turnState = outerDc.Context.TurnState["ConversationState"]; //access turn state here
    outerDc.EndDialogAsync();    
    return base.ContinueDialogAsync(outerDc, cancellationToken);
}

在内部ContinueDialogAsync,我试图访问outerDc包含我的机器人状态数据的对话框的上下文对象,正如我在即时/监视窗口中配置和看到的那样。

outerDc.Context.TurnState Count = 3
    [0]: {[BotIdentity, System.Security.Claims.ClaimsIdentity]}
    [1]: {[Microsoft.Bot.Connector.IConnectorClient, Microsoft.Bot.Connector.ConnectorClient]}
    [2]: {[ConversationState, Microsoft.Bot.Builder.BotState+CachedBotState]} outerDc.Context.TurnState["ConversationState"] {Microsoft.Bot.Builder.BotState.CachedBotState}
    Hash: "{}"
    State: Count = 2

这是 QuickWatch 表达式,突出显示的值正是我所需要的。

在此处输入图像描述

当我尝试((Microsoft.Bot.Builder.BotState.CachedBotState)outerDc.Context.TurnState["ConversationState"]).State在我的代码中使用表达式时,它似乎CachedBotState不是命名空间/包的一部分。此外,这似乎是仍处于预览阶段的 nuget 包Microsoft.Bot.Builder.BotState.CachedBotState的一部分。Microsoft.Bot.Builder.Core

我知道我可以将TurnState对象作为附加参数从对话框传递OnTurnAsync给我的对话框。但是,我想通过对话框的上下文访问它,当它显示它已经存在时。有没有办法做到这一点?

如果我可以详细说明,请告诉我。

标签: c#.netdialogbotframeworkstate-management

解决方案


首先,CachedBotState是一个内部实现细节,而不是你应该期望使用的东西。同样,您真的不应该深入研究TurnState并期望使用其中不受您控制的值,因为它也只是机器人状态如何在回合范围内维护值的实现细节。我建议您放弃这种方法,因为最终整个实现可能会在下一个版本中发生变化(因为它是内部细节并且不受 semver 规则的约束),然后您的代码会因此而中断。

相反,您应该做的是IStatePropertyAccessor<TurnState>SomeDialog创建它并将其添加到DialogSet. 这使SomeDialog您能够在给定的回合中读取/写入该特定属性,并且您的代码将改为如下所示:

public override Task<DialogTurnResult> ContinueDialogAsync(DialogContext outerDc, CancellationToken cancellationToken = default(CancellationToken))
{
    // Access state via the property accessor rather than trying to access raw internals of bot state management
    var turnState = await _turnStatePropertyAccessor.GetAsync(outerDc.Context);

    outerDc.EndDialogAsync();    

    return base.ContinueDialogAsync(outerDc, cancellationToken);
}

推荐阅读