我无法弄清楚如何在MS Bot Framework中做一个非常简单的事情:允许用户突破任何对话,离开当前对话框并通过键入“quit”返回主菜单,“退出“或”重新开始“。
以下是我的主要对话设置方式:
public async Task<HttpResponseMessage> Post([FromBody]Activity activity)
{
try
{
if (activity.Type == ActivityTypes.Message)
{
UserActivityLogger.LogUserBehaviour(activity);
if (activity.Text.ToLower() == "start over")
{
//Do something here, but I don't have the IDialogContext here!
}
BotUtils.SendTyping(activity); //send "typing" indicator upon each message received
await Conversation.SendAsync(activity, () => new RootDialog());
}
else
{
HandleSystemMessage(activity);
}
}
我知道如何使用context.Done<DialogType>(this);
终止对话框,但在此方法中,我无法访问IDialogContext对象,因此无法调用.Done()
。
当用户键入某个消息时,除了在所有对话框的每个步骤中添加一个检查之外,还有其他方法可以终止整个对话框堆栈吗?
发布赏金:
我需要一种终止所有IDialog
的方法,而不使用我在此处发布的令人发指的黑客攻击(删除我需要的所有用户数据,例如用户设置和首选项)。
基本上,当用户键入“退出”或“退出”时,我需要退出当前正在进行的任何IDialog
并返回到新状态,就好像用户刚刚发起了对话一样。
我需要能够从MessageController.cs,
执行此操作,我仍然无法访问IDialogContext
。我似乎唯一有用的数据是Activity
对象。如果有人指出其他方法,我会很高兴。
另一种方法是找到一些其他方法来检查机器人的其他位置的“退出”和“退出”关键字,而不是在Post方法中。
但它不应该是在IDialog
的每一步都完成的检查,因为代码太多甚至不可能(使用PromptDialog
时,我无法访问用户键入的文本)。
我没有探索的两种可能方式:
IDialog
,而是开始新的对话
与用户(新ConversationId
)IDialogStack
对象并使用它来管理对话框堆栈。 Microsoft文档对此对象保持沉默,因此我不知道如何获取它。我没有在机器人的任何地方使用允许Chain
的{{1}}对象,但如果您认为可以重写它以使用它,它也可以是解决此问题的方法之一。但是,我还没有找到如何在各种类型的对话框(.Switch()
和普通的FormFlow
)之间进行分支,这些对话框又调用了自己的子对话框等。
答案 0 :(得分:25)
根据我对您的问题的理解,您想要实现的是重置对话框而不会完全破坏僵尸状态。
BotDataStore&gt; BotData&gt; DialogStack 强>
从上面知道 FACTS ,我的解决方案将是
// in Global.asax.cs
var builder = new ContainerBuilder();
builder.RegisterModule(new DialogModule());
builder.RegisterModule(new ReflectionSurrogateModule());
builder.RegisterModule(new DialogModule_MakeRoot());
var config = GlobalConfiguration.Configuration;
builder.RegisterApiControllers(Assembly.GetExecutingAssembly());
builder.RegisterWebApiFilterProvider(config);
var container = builder.Build();
config.DependencyResolver = new AutofacWebApiDependencyResolver(container);
private static ILifetimeScope Container
{
get
{
var config = GlobalConfiguration.Configuration;
var resolver = (AutofacWebApiDependencyResolver)config.DependencyResolver;
return resolver.Container;
}
}
using (var scope = DialogModule.BeginLifetimeScope(Container, activity))
{
var botData = scope.Resolve<IBotData>();
await botData.LoadAsync(default(CancellationToken));
var stack = scope.Resolve<IDialogStack>();
stack.Reset();
await botData.FlushAsync(default(CancellationToken));
}
希望它有所帮助。
感谢@ejadib指出,容器已在会话类中公开。
我们可以删除上面答案中的第2步,最后代码会是
using (var scope = DialogModule.BeginLifetimeScope(Conversation.Container, activity))
{
var botData = scope.Resolve<IBotData>();
await botData.LoadAsync(default(CancellationToken));
var stack = scope.Resolve<IDialogStack>();
stack.Reset();
await botData.FlushAsync(default(CancellationToken));
}
答案 1 :(得分:8)
这是一个非常难看的黑客行为。它基本上删除了所有用户数据(您可能实际需要),这会导致会话重新启动。
如果有人知道更好的方式,而不删除用户数据,请分享。
public async Task<HttpResponseMessage> Post([FromBody]Activity activity)
{
try
{
if (activity.Type == ActivityTypes.Message)
{
//if the user types certain messages, quit all dialogs and start over
string msg = activity.Text.ToLower().Trim();
if (msg == "start over" || msg == "exit" || msg == "quit" || msg == "done" || msg =="start again" || msg == "restart" || msg == "leave" || msg == "reset")
{
//This is where the conversation gets reset!
activity.GetStateClient().BotState.DeleteStateForUser(activity.ChannelId, activity.From.Id);
}
//and even if we reset everything, show the welcome message again
BotUtils.SendTyping(activity); //send "typing" indicator upon each message received
await Conversation.SendAsync(activity, () => new RootDialog());
}
else
{
HandleSystemMessage(activity);
}
}
答案 2 :(得分:2)
我知道这有点旧,但我遇到了同样的问题,而且发布的解决方案不再是最好的方法了。
我不确定自哪个版本可用,但是在3.8.1上你可以注册可以在对话框的任何地方触发的IScorable
服务。
有一个示例代码显示它是如何工作的,它有一个“取消”全局命令处理程序:
https://github.com/Microsoft/BotBuilder-Samples/tree/master/CSharp/core-GlobalMessageHandlers
代码的一部分如下所示:
protected override async Task PostAsync(IActivity item, string state, CancellationToken token)
{
this.task.Reset();
}
答案 3 :(得分:0)
适用于其他人的其他代码:
private async Task _reset(Activity activity)
{
await activity.GetStateClient().BotState
.DeleteStateForUserWithHttpMessagesAsync(activity.ChannelId, activity.From.Id);
var client = new ConnectorClient(new Uri(activity.ServiceUrl));
var clearMsg = activity.CreateReply();
clearMsg.Text = $"Reseting everything for conversation: {activity.Conversation.Id}";
await client.Conversations.SendToConversationAsync(clearMsg);
}
此代码由用户mmulhearn在此发布:https://github.com/Microsoft/BotBuilder/issues/101#issuecomment-316170517