C# 当用户键入“时,终止所有对话框并退出MS Bot Framework中的对话”;退出“&引用;“退出”;等

C# 当用户键入“时,终止所有对话框并退出MS Bot Framework中的对话”;退出“&引用;“退出”;等,c#,bots,botframework,C#,Bots,Botframework,我不知道如何在MS Bot框架中完成一件非常简单的事情:允许用户中断任何对话,离开当前对话框并通过键入“退出”、“退出”或“重新开始”返回主菜单 以下是我的主要对话的安排方式: public async Task<HttpResponseMessage> Post([FromBody]Activity activity) { try { if (activity.Type == ActivityTypes.Mes

我不知道如何在MS Bot框架中完成一件非常简单的事情:允许用户中断任何对话,离开当前对话框并通过键入“退出”、“退出”或“重新开始”返回主菜单

以下是我的主要对话的安排方式:

    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);
            }
        }
公共异步任务发布([FromBody]活动)
{
尝试
{
if(activity.Type==ActivityTypes.Message)
{
LogUserBehavior(活动);
if(activity.Text.ToLower()=“重新开始”)
{
//在这里做点什么,但我这里没有IDialogContext!
}
BotUtils.SendTyping(活动);//在收到每条消息时发送“typing”指示符
wait Conversation.sendaync(活动,()=>newrootdialog());
}
其他的
{
HandleSystemMessage(活动);
}
}
我知道如何使用
context.Done(this);
终止对话框,但在这种方法中,我没有访问IDialogContext对象的权限,因此无法调用
.Done()

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

发布赏金:

我需要一种方法来终止所有
IDialog
s,而不使用我在这里发布的骇人听闻的黑客(它删除我需要的所有用户数据,例如用户设置和首选项)

基本上,当用户键入“退出”或“退出”时,我需要退出当前正在进行的任何
IDialog
,并返回到新状态,就像用户刚刚启动了一个对话一样

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

另一种方法是找到其他方法,在bot的其他位置检查“exit”和“quit”关键字,而不是在Post方法中

但这不应该是在
IDialog
的每一步都要进行的检查,因为这太多代码,甚至不总是可能的(当使用
PrompDialog
时,我无法访问用户键入的文本)

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

  • 开始新的对话,而不是终止所有当前的
    IDialog
    s 与用户(新建
    会话ID
  • 获取
    IDialogStack
    对象,并对其执行一些操作以管理对话框堆栈

Microsoft文档对此对象没有提示,因此我不知道如何获取它。我不使用允许
.Switch()的
对象
在bot中的任何地方,但是如果您认为可以重写它来使用它,它也可以是解决这个问题的方法之一。但是,我还没有找到如何在各种类型的对话框之间进行分支(
FormFlow
和普通的
IDialog
)然后调用自己的子对话框等。

这是一个非常丑陋的黑客程序。它基本上删除了所有用户数据(您可能确实需要这些数据),这会导致对话重新启动

如果有人知道更好的方法,在不删除用户数据的情况下,请分享

    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);
            }
        }
公共异步任务发布([FromBody]活动)
{
尝试
{
if(activity.Type==ActivityTypes.Message)
{
//如果用户键入某些消息,请退出所有对话框并重新开始
字符串msg=activity.Text.ToLower().Trim();
如果(msg==“重新开始”| | msg==“退出”| | msg==“退出”| | msg==“完成”| | msg==“重新启动”| | msg==“离开”| msg==“重置”)
{
//这就是重新设置对话的地方!
activity.GetStateClient().BotState.DeleteStateForUser(activity.ChannelId,activity.From.Id);
}
//即使我们重置了所有内容,也要再次显示欢迎信息
BotUtils.SendTyping(活动);//在收到每条消息时发送“typing”指示符
wait Conversation.sendaync(活动,()=>newrootdialog());
}
其他的
{
HandleSystemMessage(活动);
}
}
问题分解 根据我对您问题的理解,您想要实现的是在不完全破坏bot状态的情况下重置对话框堆栈


事实(我从github存储库中读到)
  • 框架如何保存对话框堆栈,如下所示:
  • BotDataStore>BotData>DialogStack

  • BotFramework使用AutoFac作为DI容器
  • DialogModule是他们用于对话框组件的Autofac模块

  • 如何做 从上面了解事实,我的解决方案是

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

  • 获取Autofac容器(您可以随意在代码中放置您喜欢的任何地方)

  • 范围中加载BotData
  • 加载对话框堆栈
  • 重置对话框堆栈
  • 将新的BotData推回到BotDataStore

  • 使用(var scope=DialogModule.BeginLifetimeScope(容器,活动))
    {
    var botData=scope.Resolve();
    等待botData.LoadAsync(默认值(CancellationToken));
    var stack=scope.Resolve();
    
    // 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));
    }
    
    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));
    }
    
    protected override async Task PostAsync(IActivity item, string state, CancellationToken token)
    {
        this.task.Reset();
    }
    
    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);
        }