当用户键入"退出","退出"等时,终止所有对话框并退出MS Bot Framework中的对话

25 c# bots botframework

我无法弄清楚如何在MS Bot Framework中做一个非常简单的事情:允许用户打破任何对话,离开当前对话框并通过键入"quit","exit"或"返回主菜单"重来".

这是我的主要对话设置方式:

    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);
            }
        }
Run Code Online (Sandbox Code Playgroud)

我知道如何终止一个对话框context.Done<DialogType>(this);,但在这个方法中,我没有访问IDialogContext对象,所以我无法调用.Done().

当用户键入某个消息时,除了在所有对话框的每个步骤中添加一个检查之外,还有其他方法可以终止整个对话框堆栈吗?

发表赏金:

我需要一种方法来终止所有IDialogs而不使用我在这里发布的令人发指的黑客攻击(删除我需要的所有用户数据,例如用户设置和首选项).

基本上,当用户键入"退出"或"退出"时,我需要退出IDialog当前正在进行的任何操作并返回到新状态,就好像用户刚刚发起了对话一样.

我需要能够从MessageController.cs,我仍无法访问的地方执行此操作IDialogContext.我似乎唯一有用的数据是Activity对象.如果有人指出其他方法,我会很高兴.

另一种方法是找到一些其他方法来检查机器人的其他位置的"退出"和"退出"关键字,而不是在Post方法中.

但它不应该是在每一步都完成的检查IDialog,因为这是太多的代码,甚至不可能(当使用时PromptDialog,我无法访问用户输入的文本).

我没有探索的两种可能方式:

  • 而不是终止所有当前的IDialogs,与用户开始新的对话(新ConversationId)
  • 获取IDialogStack对象并使用它来管理对话框堆栈.

Microsoft文档对此对象保持沉默,因此我不知道如何获取它.我不使用Chain允许.Switch()机器人中任何位置的对象,但如果您认为可以重写它以使用它,它也可以是解决此问题的方法之一.但是,我还没有找到如何在各种类型的对话框(FormFlow和普通对象IDialog)之间进行分支,这些对话框又称为自己的子对话框等.

Kie*_*Chu 27

问题突破

根据我对您的问题的理解,您想要实现的是重置对话框而不会完全破坏机器人状态.


FACTS(从我从github存储库中读取的内容)

  1. 框架如何保存对话框堆栈如下:

BotDataStore> BotData> DialogStack

  1. BotFramework使用AutoFac作为DI容器
  2. DialogModule是用于对话框组件的Autofac模块

怎么做

从上面了解FACTS,我的解决方案就是

  1. 注册依赖项,以便我们可以在我们的控制器中使用:

// 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);
Run Code Online (Sandbox Code Playgroud)
  1. 获取Autofac容器(随意放置在您熟悉的代码中的任何位置)

private static ILifetimeScope Container
{
    get
    {
        var config = GlobalConfiguration.Configuration;
        var resolver = (AutofacWebApiDependencyResolver)config.DependencyResolver;
        return resolver.Container;
    }
}
Run Code Online (Sandbox Code Playgroud)
  1. 范围中加载BotData
  2. 加载DialogStack
  3. 重置DialogStack
  4. 将新的BotData推回到BotDataStore

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));
}
Run Code Online (Sandbox Code Playgroud)

希望能帮助到你.


更新1(2016年8月27日)

感谢@ejadib指出,Container已经在会话类中公开了.

我们可以在上面的答案中删除第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));
}
Run Code Online (Sandbox Code Playgroud)


小智 9

这是一个非常难看的黑客行为.它基本上删除了所有用户数据(您可能实际需要),这会导致会话重新启动.

如果有人知道更好的方法,而不删除用户数据,请分享.

    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);
            }
        }
Run Code Online (Sandbox Code Playgroud)