嵌套对话框:消息被发送两次

Nested dialogs: message being sent twice

我有一个机器人,我正在做这样的事情:

1) 一条新的 Activity(消息)到达。

2) 我将消息发送到 RootDialog。

3) 根据某些逻辑,RootDialog 可以:

 a) Call a LuisDialog (handling natural language)

 b) Call a CustomDialog (handles some business logic).

但是当用户状态被重置,并且流程导致LuisDialog内部的意图时,它调用了两次意图方法。只是第一次状态为空,然后就正常了。

让我给你看代码:

消息控制器:

   public async Task<HttpResponseMessage> Post([FromBody]Activity activity)
    {
        if (activity.Type == ActivityTypes.Message)
        {
            ConnectorClient connector = new ConnectorClient(new Uri(activity.ServiceUrl));
            try
            {
                await Conversation.SendAsync(activity, () => new RootDialog());
            }
            catch (HttpRequestException e)
            {
             ...
            }
     }

根对话框:

 public class RootDialog : IDialog<object>
 {
    public async Task StartAsync(IDialogContext context)
    {
        await MessageReceivedAsync(context, Awaitable.FromItem(context.Activity.AsMessageActivity()));
    }

    private async Task MessageReceivedAsync(IDialogContext context, IAwaitable<IMessageActivity> awaitable)
    {
        bool value = DoSomeCustomLogic();
        if (value) 
        {
            string message = DoSomething();
            await context.PostAsync(message);
        } else {
            bool value2 = DoSomeCustomLogic2();
            if (value2) 
            {
                var answerValidationDialog = new ValidateAnswerWithUserDialog();
                context.Call(answerValidationDialog, ValidateAnswerWithUserDialogCompletedCallback);
            } else {
                var luisDialog = new LuisDialog();
                await context.Forward(luisDialog,LuisDialogCompletedCallback, context.Activity, CancellationToken.None);
            }
        }
    }

回调只做 context.Done(true);

而 LuisDialog 有一个 Intention 是这样的:

  [LuisIntent(LuisUtils.INTENT_MENU_SALUTE)]
    public async Task SaluteOrMenu(IDialogContext context, LuisResult result)
    {
        if (LuisUtils.IntentScoreIsHighEnough(result))
        {
            string userName = context.Activity.From.Name;
            ContextHelper helper = new ContextHelper(MessageReceived);
            await helper.AskUserToDoSomeInitialAction(context, saluteWord, userName);
            context.Done(true);
        }
        else
        {
            await None(context, result);
        }
    }

最后 class ContextHelper:

public class ContextHelper
{
    private Func<IDialogContext, IAwaitable<IMessageActivity>, Task> MessageReceived;

    public ContextHelper(Func<IDialogContext, IAwaitable<IMessageActivity>, Task> messageReceived)
    {
        MessageReceived = messageReceived;
    }

    public async Task AskUserToDoSomeInitialAction(IDialogContext context, string saluteWord, string userName)
    {
        var reply = context.MakeMessage();
        List<CardAction> buttons = BuildInitialOptionActions();
        List<CardImage> images = BuildInitialOptionImages();
        string initialText = $"Hi stranger!"
        var card = new HeroCard
        {
            Title = "Hello!"
            Text = initialText,
            Buttons = buttons,
            Images = images
        };
        reply.Attachments = new List<Attachment> { card.ToAttachment() };
        await context.PostAsync(reply);
        context.Wait(AfterUserChoseOptionInSalute);
    }

    private async Task AfterUserChoseOptionInSalute(IDialogContext context, IAwaitable<IMessageActivity> result)
    {
        await ReDispatchMessageReceivedToDialog(context);
    }

    private async Task ReDispatchMessageReceivedToDialog(IDialogContext context)
    {
        await MessageReceived(context, Awaitable.FromItem(context.Activity.AsMessageActivity()));
    }

}

SaluteOrMenu Intention 被调用两次(仅在我第一次与机器人交互或删除状态时调用。调试后我看到在执行 context.Wait(AfterUserChoseOptionInSalute); 后,机器人调用该函数(而不是等待用于调用它的事件)

有什么想法吗?

提前致谢。

我找到了错误的那一行。它在第一个对话框(RootDialog)上:

public async Task StartAsync(IDialogContext context)
{
   await MessageReceivedAsync(context, Awaitable.FromItem(context.Activity.AsMessageActivity()));
}

那是用传入 activity 重新发送消息的行。我把它放在一些代码块中的某个地方并且(不知道为什么)认为在 StartAsync 上使用它是个好主意。因此,正因为如此,发生了两次呼叫。

我傻了。

我只是把它改成了这个并工作:

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