Botframework 将状态传播到MS框架中的对话框

Botframework 将状态传播到MS框架中的对话框,botframework,microsoft-bot-framework,Botframework,Microsoft Bot Framework,在MicrosoftBotFramework v4中,通常通过将状态(UserState、ConversationState、PrivateCversationState)作为参数传递给对话框的构造函数,将其传播到对话框中 这样: Startup.cs 公共类启动 { public void配置服务(IServiceCollection服务) { // ... IStorage storage=new MemoryStorage();//仅用于测试! AddSingleton(新用户状态(存储)

在MicrosoftBotFramework v4中,通常通过将状态(UserStateConversationStatePrivateCversationState)作为参数传递给对话框的构造函数,将其传播到对话框中

这样:

Startup.cs

公共类启动
{
public void配置服务(IServiceCollection服务)
{
// ...
IStorage storage=new MemoryStorage();//仅用于测试!
AddSingleton(新用户状态(存储));
AddSingleton(新会话状态(存储));
// ...
services.AddSingleton();
AddSingleton(x=>newRootDialog(
x、 GetRequiredService(),
x、 GetRequiredService()
);
services.AddTransient();
}
}
Bot.cs

public类Bot:ActivityHandler其中T:Dialog
{
对话;
BotState\u userState,\u conversationState;
公共Bot(T对话框、用户状态、用户状态、会话状态、会话状态)
{
_userState=userState;
_会话状态=会话状态;
_对话=对话;
}
公共覆盖异步任务OnTurnAsync(ITurnContext上下文,CancellationToken CancellationToken=default)
{
wait base.OnTurnAsync(上下文,cancellationToken);
wait_userState.saveChangesSync(上下文);
wait_conversationState.SaveChangesAsync(上下文);
}
受保护的重写异步任务OnMessageActivityAsync(ITurnContext上下文,CancellationToken CancellationToken)
{
wait _dialog.RunAsync(上下文,_conversationState.CreateProperty(nameof(DialogState)),cancellationToken);
}
}
RootDialog.cs

公共类RootDialog:ComponentDialog
{
用户状态_UserState;
会话状态_会话状态;
publicRootDialog(UserState-uState,ConversationState-cState):base(“id”)
{
_userState=uState;
_会话状态=cState;
//添加一些对话框并将状态作为参数传递
AddDialog(新CustomDialog_1(uState,cState));
AddDialog(新CustomDialog_2(uState,cState));
// ...
AddDialog(新CustomDialog_N(uState,cState));
}
}
现在,让我们假设那些CustomDialogs再次使用需要访问状态的其他CustomDialogs。这些状态必须作为参数一次又一次地传递给构造函数


问题是:是否有其他方法可以访问状态以避免将它们作为参数一次又一次地传递?

如何访问对话框中的状态取决于状态的范围

如果状态的作用域为对话框,则应使用对话框状态。更具体地说,应使用对话框关联对话框实例的状态属性。最近的回答中对此进行了一些讨论:

(阅读有关对话框实例的内容)。如果希望对话框跟踪任何内容,应将其放入关联的对话框实例的状态对象中,查看如何执行此操作的示例的最佳位置是SDK源代码本身。例如,您可以看到a如何跟踪自定义值以及它所处的步骤:

//更新持久化步骤索引
var state=dc.ActiveDialog.state;
状态[步骤索引]=索引;
如果状态的作用域大于一个对话框的一个实例,则可以像以前一样将bot状态对象传递给对话框。如果将对话框置于依赖项注入中,以便可以将bot状态自动注入到其构造函数中,这可能会变得更容易。如果您的对话框访问也在对话框之外使用,那么给对话框一个状态属性访问器而不是状态本身是有意义的,这样可以减少冗余并分离关注点

如果你想确保你的机器人状态在你有回合上下文的任何地方都是可访问的,实际上有一种内置的方法可以自动将你的机器人状态添加到每个回合的回合状态。这是通过扩展方法实现的:

adapter.UseBotState(userState,conversationState);
然后,您可以检索如下状态:

var userState=turnContext.TurnState.Get();
var conversationState=turnContext.TurnState.Get();

如何在对话框中访问状态取决于状态的范围

如果状态的作用域为对话框,则应使用对话框状态。更具体地说,应使用对话框关联对话框实例的状态属性。最近的回答中对此进行了一些讨论:

(阅读有关对话框实例的内容)。如果希望对话框跟踪任何内容,应将其放入关联的对话框实例的状态对象中,查看如何执行此操作的示例的最佳位置是SDK源代码本身。例如,您可以看到a如何跟踪自定义值以及它所处的步骤:

//更新持久化步骤索引
var state=dc.ActiveDialog.state;
状态[步骤索引]=索引;
如果状态的作用域大于一个对话框的一个实例,则可以像以前一样将bot状态对象传递给对话框。如果将对话框置于依赖项注入中,以便可以将bot状态自动注入到其构造函数中,这可能会变得更容易。如果您的对话框访问也在对话框之外使用,那么给对话框一个状态属性访问器而不是状态本身是有意义的,这样可以减少冗余并分离关注点

如果你想确保你的机器人状态在你有回合上下文的任何地方都是可访问的,实际上有一种内置的方法可以自动将你的机器人状态添加到每个回合的回合状态。这是通过扩展方法实现的:

adapter.UseBotState(u