MS Bot 生成器 IForm 类型无效 Exception:Has xxx 期望 yyy

MS Bot builder IForm Invalid Type Exception:Has xxx Expect yyy

我正在尝试构建一个简单的基于 iForm 的机器人。当一个表格完成后,我想展示另一个。 两种形式都包含一个枚举值。第一种形式正确显示。当我 select 一个选项时, SelectNextAction 会按预期调用。 第一个对话框是通过以下方式构造的:

  public static IForm<RootForm> BuildRootForm()
    {
        IForm<RootForm> ret  = new FormBuilder<RootForm>()
             .Message("Hi")
             .AddRemainingFields()
             .OnCompletion(SelectNextAction)
                .Build();

        return ret;
    }

    private static async Task SelectNextAction(IDialogContext context, RootForm state)
    {

        // Tell the user that the form is complete
        switch (state.Choice)
        {
            case MainChoice.Transfer:
                IFormDialog<TransferForm> form = FormDialog.FromForm(TransferForm.BuildTransferForm);
                context.Call(form, TransferDialogComplete);
                break;
            default:
                break;

        }
    }

此代码有运行后调用TransferDialogComplete

   private async static Task TransferDialogComplete(IDialogContext context, IAwaitable<TransferForm> result)
    {
        await result;
    }

然后抛出异常:

Exception: invalid type: expected EBBot.Dialogs.TransferForm, have RootForm [File of type 'text/plain']

我做错了什么?有什么想法或建议吗?

传递给 OnCompletion 方法的委托不能用于调用其他表单或任何其他对话框。

This should only be used for side effects such as calling your service wit the form state results. In any case the completed form state will be passed to the parent dialog.

Source:第 225 行

查看示例 here

如何通过 ResumeAfter 方法实现这一点。这是一个例子:

[Serializable]
public class RootDialog : IDialog<object>
{
    public async Task StartAsync(IDialogContext context)
    {
        var form = new FormDialog<SimpleForm>(new SimpleForm1(), 
        SimpleForm1.BuildForm);
        context.Call(form, ResumeAfterForm1);
    }

    private async Task ResumeAfterForm1(IDialogContext context, IAwaitable<object> result)
    {
        var form = new FormDialog<SimpleForm2>(new SimpleForm2(), 
        SimpleForm2.BuildForm, FormOptions.PromptInStart);
        context.Call(form, ResumeAfterForm2);
    }
    // other code
}

注意:我使用了 PromptInStart 因为我注意到如果您不包含它,表单将不会立即启动。

正如我在评论中提到的,问题是由于在 OnCompletion 调用中调用了第二种形式。

为了解决这个问题,您应该在调用第一个表单时指定的 ResumeAfter<T> 方法中调用第二个表单。

代码调用 RootForm

var rootForm = FormDialog.FromForm(RootForm.BuildRootForm);
context.Call(rootForm, AfterRootFormCompleted);

RootForm 完成后执行的代码

private async Task AfterRootFormCompleted(IDialogContext context, IAwaitable<RootForm> result)
{
     try 
     {
        var state = await result;
        IFormDialog<TransferForm> form = FormDialog.FromForm(TransferForm.BuildTransferForm);
        context.Call(form, TransferDialogComplete);
     }
     catch (FormCancelledException)
     {
      // do something;
     }
}