我最近加入了微软的Bot框架,这将是我第一次接触C#中的异步编程。我正在创建一个设计为选择树的提示。使用XML文档,我设计了一个用户可以选择的主题层次结构 - 然后我使用HelpTopicSelector类抽象了XML的解析。
流程如下:
- 用户类型“ help ”
- 上传到HelpDialog的上下文
- 帮助对话框创建提示,其中包含HelpTopicSelector提供的选项列表
- 当用户选择提示选项时,HelpTopicSelector“选择”选择并从子树中更新新的选项列表
- 使用更新的主题创建另一个提示
- 重复,直到最后选择的主题是最后一个节点 - 调用Context.Done
从基本对话框中调用帮助对话框,如下所示:
private async Task ActivityRecievedAsync(IDialogContext context, IAwaitable<object> result)
{
Activity activity = await result as Activity;
if (activity.Text == "test")
{
await context.PostAsync("works");
}
else if(activity.Text == "help")
{
await context.Forward(new HelpDialog(), this.ResumeAfterHelp, activity.AsMessageActivity(), System.Threading.CancellationToken.None);
await context.PostAsync("Done Selection!");
}
context.Wait(ActivityRecievedAsync);
}
我几乎可以肯定我的代码中的问题在于我的HelpDialog的“循环”性质,但我真的不知道为什么它会失败。
class HelpDialog : IDialog
{
public async Task StartAsync(IDialogContext context)
{
await context.PostAsync("Reached Help Dialog!");
context.Wait(ActivityRecievedAsync);
}
private async Task ActivityRecievedAsync(IDialogContext context, IAwaitable<object> result)
{
var message = await result;
await context.PostAsync("HelpDialog: Activity Received");
await HandleTopicSelection(context);
context.Wait(ActivityRecievedAsync);
}
private async Task HandleTopicSelection(IDialogContext context)
{
List<string> topics = HelpTopicSelector.Instance.Topics;
PromptDialog.Choice<string>(context, TopicSelectedAsync, topics, "Select A Topic:");
// Unecessary?
context.Wait(ActivityRecievedAsync);
}
private async Task TopicSelectedAsync(IDialogContext context, IAwaitable<string> result)
{
string selection = await result;
if (HelpTopicSelector.Instance.IsQuestionNode(selection))
{
await context.PostAsync($"You asked: {selection}");
HelpTopicSelector.Instance.Reset();
context.Done<string>(selection);
}
else
{
HelpTopicSelector.Instance.SelectElement(selection);
await HandleTopicSelection(context);
}
// Unecessary?
context.Wait(ActivityRecievedAsync);
}
}
我的期望:
鉴于这看起来有多酷,我对面对错误并不感到惊讶。机器人模拟器抛出“ Stack is Empty ”异常
。 尝试使用断点进行调试后,我注意到HelpDialog突然结束并在进入 TopicSelectedAsync 方法时退出(特别是在等待结果时)。 Visual Studio抛出以下异常:
无效需求:预期通话,有民意调查。
EXTRA注意: 我最初尝试在BasicDialog类中编写这个逻辑而不转发到任何其他对话框。令我惊讶的是,它几乎完美无缺。
答案 0 :(得分:2)
将其修改为帮助对话框:
Name
从像这样的父对话框调用它(使用context.Call()而不是.Forward()):
[Serializable]
public class HelpDialog : IDialog
{
public async Task StartAsync(IDialogContext context)
{
PromptDialog.Choice<string>(context, TopicSelectedAsync, HelpTopicSelector.Instance.Topics, "Select A Topic:", attempts: 3, retry: "Please select a Topic");
}
private async Task TopicSelectedAsync(IDialogContext context, IAwaitable<object> result)
{
try
{
string selection = await result as string;
if (HelpTopicSelector.Instance.IsQuestionNode(selection))
{
await context.PostAsync($"You asked: {selection}");
HelpTopicSelector.Instance.Reset();
context.Done<string>(selection);
}
else
{
await this.StartAsync(context);
}
}
catch (TooManyAttemptsException)
{
await this.StartAsync(context);
}
}
}
为Context.Wait()提供方法时,实际上是在提供一个continuation委托。从用户收到的下一条消息将最后发送到该方法.Wait()&#39; ed。如果您要转发或调用单独的对话框,则父级也不应该调用.Wait()。此外,在调用context.Done()时,之后在同一对话框中也不应该有.Wait()。