从 DialogContext 获取 TurnState 数据

Getting TurnState data from DialogContext

我正在使用 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,它包含我的机器人的状态数据,正如我在 immediate/watch window 中配置和看到的那样。

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 不是 namespace/package 的一部分。此外,Microsoft.Bot.Builder.BotState.CachedBotState 似乎是仍处于预览阶段的 Microsoft.Bot.Builder.Core nuget 包的一部分。

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

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

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

相反,您应该做的是在创建 IStatePropertyAccessor<TurnState> 时将其传递给 SomeDialog 的构造函数并将其添加到 DialogSet。这使 SomeDialog 能够 read/write 特定的 属性 对于给定的回合,您的代码将改为如下所示:

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);
}