在Azure上托管的我的(非Luis)僵尸程序应用程序有一个RootDialog,它可以处理所有传入的活动,这些活动不是可以直接在MessagesController.Post中处理的简单命令,因此:
var dialog = scope.Resolve<IDialog<object>>();
await Conversation.SendAsync(activity, () => dialog);
RootDialog实现IDialog<object>
,并在Autofac中注册。它在标准的Conversation.Container生命周期范围内得到解决。
我还有一个WebJob,它的工作是偶尔重置堆栈(杀死任何当前活动的对话框)并启动一个新的对话框,它本身可以调用其他对话框。我们称他们为DialogProactive:IDialog<object>
和DialogChild:IDialog<bool>
。
首先,重置堆栈。 &#39;消息&#39;是从保存在数据库中的ResumptionCookie获得的。
using (var scope = DialogModule.BeginLifetimeScope(Conversation.Container, message))
{
var botData = scope.Resolve<IBotData>();
await botData.LoadAsync(default(CancellationToken));
var stack = scope.Resolve<IDialogStack>();
stack.Reset();
await botData.FlushAsync(default(CancellationToken));
await userInfo.ResetUserStateDBAsync();
}
然后由bot发起一个对话框:
using (var scope = DialogModule.BeginLifetimeScope(Conversation.Container, message))
{
var botData = scope.Resolve<IBotData>();
await botData.LoadAsync(default(CancellationToken));
var stack = scope.Resolve<IDialogTask>();
IDialog<object> dialog = null;
dialog = scope.ResolveNamed<IDialog<object>>("ProactiveDialog",
new NamedParameter("Param1", p1),
new NamedParameter("dialogName", "DialogChild));
stack.Call(dialog.Void<object, IMessageActivity>(), null);
await stack.PollAsync(CancellationToken.None);
await botData.FlushAsync(CancellationToken.None);
}
ProactiveDialogA解析IComponentContext
并继续解析并在其自己的StartAsync中调用DialogChild:
....
context.Call(newDialogChild, this.DialogDone);
此DialogChild会调用context.Done(true)
,因此ProactiveDialog的DialogDone
会自动调用&#39; true&#39;结果。它本身调用context.Done(null)
,一切都已完成。
但是下次用户向僵尸程序发送消息时,RootDialog会尝试处理它(请参阅上面的问题的开头),Conversation.SendAsync(...)
失败并出现InvalidOperationException - Stack为空(并且所以用户看到了“对不起,我的机器人代码有问题。”#);
之后很好 - 我假设发生了某种内部重置。
这是为什么?我以为我们会回到起点,并且会创建一个新的RootDialog并将其放在空堆栈上。为什么这个例外?
是否与WebJob中使用的ResumptionCookie在机器人启动的对话框完成后与后续交互不同步?
使用3.5.3。感谢。