在不将UserState注入每个对话框的情况下访问模型/数据库 [英] Accessing model/database without injecting the UserState to every dialog
问题描述
我正在从旧的botframework v4迁移到最新版本.我大约有50个对话框类,要在所有这些对话框上注入用户状态依赖关系,需要做很多工作.
I am migrating from the old botframework v4 to the latest version. I have around 50 dialog classes and it is so much work to inject the userstate dependency on all of them.
在我可以通过以下代码访问模型之前:
Before i can access the model by just this code:
var userstate = await (stepContext.Context.TurnState["BasicAccessors"] as BasicAccessors).BasicUserStateAccessor.GetAsync(stepContext.Context);
,无需在每个对话框中插入userState.我尝试这样做,但出现500个错误和其他错误.如何将这种方法复制到最新版本?
and no need to inject the userState in every dialog. I tried doing this but got 500 error and other ones. How can i replicate this method to the latest version?
这是旧版本中的代码.
BasicAccessors类:
BasicAccessors class:
public class BasicAccessors
{
public BasicAccessors(ConversationState conversationState, UserState userState)
{
ConversationState = conversationState ?? throw new ArgumentNullException(nameof(conversationState));
UserState = userState ?? throw new ArgumentException(nameof(userState));
}
public static string DialogStateAccessorName { get; } = $"{nameof(BasicAccessors)}.DialogState";
public static string BasicUserStateAccessorName { get; } = $"{nameof(BasicAccessors)}.BasicUserState";
public IStatePropertyAccessor<BasicUserState> BasicUserStateAccessor { get; internal set; }
public IStatePropertyAccessor<DialogState> DialogStateAccessor { get; internal set; }
public ConversationState ConversationState { get; }
public UserState UserState { get; }
}
OnTurnAsync:
OnTurnAsync:
turnContext.TurnState.Add("BasicAccessors", _basicAccessors);
启动:
services.AddSingleton<BasicAccessors>(sp =>
{
var options = sp.GetRequiredService<IOptions<BotFrameworkOptions>>().Value;
var conversationState = options.State.OfType<ConversationState>().FirstOrDefault();
var userState = options.State.OfType<UserState>().FirstOrDefault();
var accessors = new BasicAccessors(conversationState, userState)
{
DialogStateAccessor = conversationState.CreateProperty<DialogState>(BasicAccessors.DialogStateAccessorName),
BasicUserStateAccessor = userState.CreateProperty<BasicUserState>(BasicAccessors.BasicUserStateAccessorName),
};
return accessors;
});
推荐答案
我实际上只是您已经具有-accessors
类.您只需要将其更改为类似以下内容(调整以匹配您的代码)即可:
You already have an -accessors
class. You just need to change it to something more like this (adjust to match your code):
using Microsoft.Bot.Builder;
using Microsoft.BotBuilderSamples;
namespace Microsoft.BotBuilderSamples
{
public class BasicAccessors
{
public IStatePropertyAccessor<ConversationData> ConversationStateAccessors { get; }
public IStatePropertyAccessor<UserProfile> UserStateAccessors { get; }
public StateAccessors(ConversationState conversationState, UserState userState)
{
ConversationStateAccessors = conversationState.CreateProperty<ConversationData>(nameof(ConversationData));
UserStateAccessors = userState.CreateProperty<UserProfile>(nameof(UserProfile));
}
}
}
注意如何分别通过*State.CreateProperty<*>(nameof(*));
然后,在Startup.cs
中,您只需要:
Then, in Startup.cs
, you just need:
services.AddSingleton<StateAccessors>();
services.AddSingleton<MyDialogThatNeedsAccessors>(); // Call this for each of your Dialogs
然后,在需要访问器的对话框中,
Then, in your dialogs that need the accessors,
public MyDialogThatNeedsAccessors(BasicAccessors stateAccessors)
{
_userProfileAccessor = stateAccessors.UserStateAccessors;
}
然后,要在对话框中访问它,您只需执行以下操作:
Then, to access it within your dialog, you just do something like:
var userProfile = await _userProfileAccessor.GetAsync(stepContext.Context, () => new UserProfile());
对于不需要访问器的对话框,只需将其保留在构造函数之外即可.
For dialogs that don't need the accessors, just leave it out of the constructor.
这篇关于在不将UserState注入每个对话框的情况下访问模型/数据库的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!