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;
}
}
我正在尝试构建一个简单的基于 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;
}
}