【问题标题】:Bot Framework's context.Wait() not waiting for user inputBot Framework 的 context.Wait() 不等待用户输入
【发布时间】:2018-04-26 11:24:04
【问题描述】:

我开始开发一个简单的 Bot,从文档中的 Echo bot 演变而来。而且我很快就遇到了问题。

我的 RootDialog 上有这三种方法:

public async Task StartAsync(IDialogContext context)
{
   await context.PostAsync("Olá! Eu sou um bot!");
   await context.PostAsync("Qual é o teu nome?");

   context.Wait(NameReceivedAsync);
}

private async Task NameReceivedAsync(IDialogContext context, IAwaitable<object> result)
{
   var activity = await result as Activity;

   userName = activity.Text;

   await context.PostAsync($"Olá {userName}. Podes dizer alguma coisa e eu vou repetir.");

   context.Wait(MessageReceivedAsync);
}

private async Task MessageReceivedAsync(IDialogContext context, IAwaitable<object> result)
{
   var activity = await result as Activity;

   // calculate something for us to return
   int length = (activity.Text ?? string.Empty).Length;

   // return our reply to the user
   await context.PostAsync($"Tu disseste { activity.Text}, que tem {length} caracteres");

   context.Wait(MessageReceivedAsync);
}

而我的 MessageController Post 方法是这样的:

public async Task<HttpResponseMessage> Post([FromBody]Activity activity)
{
   await Conversation.SendAsync(activity, () => new Dialogs.RootDialog());

   return new HttpResponseMessage(System.Net.HttpStatusCode.Accepted);
}

这个想法是让机器人立即发送两条消息,等待用户输入用户名,发送另一条消息,然后转到 MessageReceivedAsync,在那里他将开始他的回声循环。问题是机器人没有等待输入,只在 MessageReceivedAsync 结束时停止,在那里他将开始回显。

我似乎无法理解为什么会发生这种情况,因为据我所见,context.Wait(...) 应该让 Bot 等待输入,而这并没有发生。我正在使用 Chrome 上的 Bot Framework Channel Emulator 对其进行测试,如果这有什么不同的话。

【问题讨论】:

  • context.Wait 可以等待吗?
  • @PaulSuart 方法参考是here。它不可等待,它需要一个异步委托
  • 但是在本教程中,据我所见,他们没有做任何比我在 context.Wait 调用之后所做的更多的事情。 docs.microsoft.com/en-us/bot-framework/dotnet/…@PaulSuart
  • 与我调用上下文时相同。在 MessageReceivedAsync 结束时等待,因为他在那里等待输入,然后再次发送消息。 @PanagiotisKanavos

标签: c# .net bots botframework


【解决方案1】:

context.Wait(method) 有点令人困惑,因为它实际上设置了一个“继续委托以指定在收到新消息时应调用的方法”来自:https://docs.microsoft.com/en-us/bot-framework/dotnet/bot-builder-dotnet-dialogs#implementation-details 但是,context.Wait(method) ) 中的 .StartAsync 将立即执行“方法”,因为对话框是第一次运行。

如果您将代码更改为以下内容,它应该可以按预期工作:

[Serializable]
    public class RootDialogTest : IDialog<object>
    {
        public async Task StartAsync(IDialogContext context)
        {
            context.Wait(NameReceivedAsync);
        }

        private async Task NameReceivedAsync(IDialogContext context, IAwaitable<object> result)
        {
            var activity = await result as Activity;

            if (!context.UserData.ContainsKey("askedname"))
            {
                await context.PostAsync("Olá! Eu sou um bot!");
                await context.PostAsync("Qual é o teu nome?");
                context.UserData.SetValue("askedname", true);
                context.Wait(NameReceivedAsync);
            }
            else
            {
                var userName = activity.Text;                
                await context.PostAsync($"Olá {userName}. Podes dizer alguma coisa e eu vou repetir.");
                context.Wait(MessageReceivedAsync);
            }
        }

        private async Task MessageReceivedAsync(IDialogContext context, IAwaitable<object> result)
        {
            var activity = await result as Activity;

            // calculate something for us to return
            int length = (activity.Text ?? string.Empty).Length;

            // return our reply to the user
            await context.PostAsync($"Tu disseste { activity.Text}, que tem {length} caracteres");

            context.Wait(MessageReceivedAsync);
        }
    }

编辑:另一个选项,对当前对话框的更改更少:

[Serializable]
public class RootDialogTest : IDialog<object>
{
    public async Task StartAsync(IDialogContext context)
    {
        await context.PostAsync("Olá! Eu sou um bot!");
        await context.PostAsync("Qual é o teu nome?");

        context.Wait(SetupMethodWait);
    }
    private async Task SetupMethodWait(IDialogContext context, IAwaitable<object> result)
    {
        context.Wait(NameReceivedAsync);
    }

    private async Task NameReceivedAsync(IDialogContext context, IAwaitable<object> result)
    {
        var activity = await result as Activity;

        var userName = activity.Text;

        await context.PostAsync($"Olá {userName}. Podes dizer alguma coisa e eu vou repetir.");

        context.Wait(MessageReceivedAsync);
    }

    private async Task MessageReceivedAsync(IDialogContext context, IAwaitable<object> result)
    {
        var activity = await result as Activity;

        // calculate something for us to return
        int length = (activity.Text ?? string.Empty).Length;

        // return our reply to the user
        await context.PostAsync($"Tu disseste { activity.Text}, que tem {length} caracteres");

        context.Wait(MessageReceivedAsync);
    }
}

【讨论】:

  • 尝试了你的第一个解决方案,仍然不行,在询问名称后仍然不停地等待输入。只在最后一个 PostAsync 停止...
  • 我想可能是因为控制器的 Post 方法。
  • context.Wait(continuationmethod) 并不意味着代码执行应该冻结并在这一行等待。它是一个延续委托......让机器人框架知道对话处理的下一条消息应该由“延续方法”处理。
【解决方案2】:

从我使用 Bot Framework 开发的情况来看,Conversation.SendAsync() 的工作方式类似于 context.Forward() 将消息转发到 RootDialog()

我建议使用AskNameDialog() 将用户引导至一个单独的对话框,使用context.Call() 并在那里处理您的代码。

查看 BotBuilder 提供的示例 https://github.com/Microsoft/BotBuilder-Samples他们应该可以帮助你理解。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2021-02-07
    • 1970-01-01
    • 1970-01-01
    • 2016-05-06
    • 1970-01-01
    • 2019-01-23
    • 2020-04-13
    • 1970-01-01
    相关资源
    最近更新 更多