Bot Framework 始终触发 Dialog 的相同方法

Bot Framework always fires sames method of Dialog

我正在玩 Bot Framework 的例子,做了一个简单的 Dialog,意在向用户致敬。我遇到的问题是在提示输入用户名后,resume 方法永远不会触发。它总是 returns 到 ConverstationStartedAsync 方法。知道为什么吗?

这是对话框:

    public class HelloDialog : IDialog<string>
{

    public async Task StartAsync(IDialogContext context)
    {
        context.Wait(ConversationStartedAsync);
    }

    public async Task ConversationStartedAsync(IDialogContext context, IAwaitable<IMessageActivity> argument)
    {
        var message = await argument;
        PromptDialog.Text(
            context: context, 
            resume: AfterNameInput, 
            prompt: "Hi! what's your name?", 
            retry: "Sorry, I didn't get that.");

    }

    public async Task AfterNameInput(IDialogContext context, IAwaitable<string> result)
    {
        var name = await result;
        PromptDialog.Text(context, AfterAskNeed, "Hi {name}. How can I help you?", "Sorry, I didn't get that.", 3);
    }

这是 MessagesController 中的操作:

        public async Task<HttpResponseMessage> Post([FromBody]Activity activity)
    {
        if (activity != null)
        {
            // one of these will have an interface and process it
            switch (activity.GetActivityType())
            {
                case ActivityTypes.Message:
                    try
                    {
                        await Conversation.SendAsync(activity, () => new HelloDialog());
                    }
                    catch(Exception ex)
                    {

                    }
                    break;

                case ActivityTypes.ConversationUpdate:
                case ActivityTypes.ContactRelationUpdate:
                case ActivityTypes.Typing:
                case ActivityTypes.DeleteUserData:
                default:
                    break;
            }
        }
        return new HttpResponseMessage(System.Net.HttpStatusCode.Accepted);
    }

我真的不知道发生了什么,但我可以通过卸载软件包 Microsoft.Bot.Builder (v3.0) 然后升级到 v3.3.3 来解决它。

当我在代码中犯了一个错误,然后修复并重新部署代码时,我就遇到了这种情况。但是,由于 Bot Framework 保存了状态,您可能会在使用旧逻辑时遇到困难。

在 Facebook 上,您可以通过键入 /deleteprofile 重新启动清除保存的状态,而在模拟器中只需创建一个新对话或 closing/reopening 模拟器即可。

As MSDN said it (https://docs.microsoft.com/en-us/bot-framework/dotnet/bot-builder-dotnet-manage-conversation-flow):

Dialog lifecycle

When a dialog is invoked, it takes control of the conversation flow. Every new message will be subject to processing by that dialog until it either closes or redirects to another dialog. In C#, you can use context.Wait() to specify the callback to invoke the next time the user sends a message. To close a dialog and remove it from the stack (thereby sending the user back to the prior dialog in the stack), use context.Done(). You must end every dialog method with context.Wait(), context.Fail(), context.Done(), or some redirection directive such as context.Forward() or context.Call(). A dialog method that does not end with one of these will result in an error (because the framework does not know what action to take the next time the user sends a message).

解决方法是优雅退出Dialog, 有关完整示例,请参见下面的代码

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

            public async Task ConversationStartedAsync(IDialogContext context, IAwaitable<IMessageActivity> argument)
            {
                var message = await argument;
                PromptDialog.Text(
                    context: context,
                    resume: AfterNameInput,
                    prompt: "Hi! what's your name?",
                    retry: "Sorry, I didn't get that.");

            }

            public async Task AfterNameInput(IDialogContext context, IAwaitable<string> result)
            {
                var name = await result;
            //Set value in the context, like holding value in ASP.NET Session
            context.PrivateConversationData.SetValue<string>("Name", name);

                PromptDialog.Choice(context, this.ResumeAfterTakingGender, new[] { "Male", "Female" }, "Please enter your gender", "I am sorry I didn't get that, try selecting one of the options below", 3);
            }

        private async Task ResumeAfterTakingGender(IDialogContext context, IAwaitable<string> result)
        {
            string gender = await result;

            string name = string.Empty;
            
            //Get the data from the context
            context.PrivateConversationData.TryGetValue<string>("Name", out name);

            await context.PostAsync($"Hi {name} you are a {gender}");

            //Gracefully exit the dialog, because its implementing the IDialog<object>, so use 
            context.Done<object>(null);
        }
      }
    }