Bot Framework技术问询:在消息线程中插入消息后如何终止对话
解决Teams Bot自适应卡片提交后触发初始选择提示的问题
你的问题核心在于:当Bot处于等待用户选择初始选项的对话状态时,自适应卡片提交的消息会被路由到当前等待的对话步骤,而卡片提交的内容不是有效的选择项,导致Prompt重新触发初始选择提示。下面提供几种可行的解决方案,都可以兼容你使用RootDialog类方法的需求:
方案一:在RootDialog中提前捕获卡片提交的消息
通过重写RootDialog的MessageReceivedAsync方法,优先处理自适应卡片提交的消息,避免其进入选择提示的重试逻辑:
public override async Task MessageReceivedAsync(IDialogContext context, IAwaitable<IMessageActivity> result) { var incomingActivity = await result; // 检查是否是自适应卡片提交的消息(通过Value属性判断) if (incomingActivity.Value != null) { // 反序列化提交的数据到你定义的模型类 var submittedData = JsonConvert.DeserializeObject<YourCardDataModel>(incomingActivity.Value.ToString()); // 调用RootDialog内的方法处理提交的数据,这里可以使用context对象操作状态或发送回复 await HandleCardSubmission(context, submittedData); // 结束当前等待的对话步骤,避免继续触发选择提示 context.Done<object>(null); return; } // 如果不是卡片提交,交给默认的对话流程处理(比如初始选择提示) await base.MessageReceivedAsync(context, result); } // 你可以在RootDialog中新增这个方法来处理卡片提交 private async Task HandleCardSubmission(IDialogContext context, YourCardDataModel data) { // 这里可以使用context收集/存储数据,比如保存到用户状态 context.UserData.SetValue("SubmittedNote", data.newnote); // 向用户发送确认消息 await context.PostAsync($"Thanks for your submission! We received: {data.newnote}"); // 如果需要,可重新启动初始选择流程,或者进入其他对话步骤 // context.Wait(ShowInitOptions); }
方案二:在MessageController中终止当前对话栈再处理提交
如果需要在API层面先拦截卡片提交,可以修改ApiController的PostAsync方法,先结束当前对话栈,再处理数据:
public async Task<HttpResponseMessage> PostAsync([FromBody]Activity activity) { if (activity.Type == ActivityTypes.Message) { // 判断是否为自适应卡片提交 if (activity.Value != null) { var dialogState = activity.GetState<DialogState>(); var dialogContext = new DialogContext(ConversationContainer, activity, dialogState); // 终止当前对话栈,清除等待状态 await dialogContext.EndDialogAsync(); // 处理提交的数据,这里可以实例化RootDialog调用其方法 var rootDialog = new RootDialog(); var submittedData = JsonConvert.DeserializeObject<YourCardDataModel>(activity.Value.ToString()); await rootDialog.HandleCardSubmission(dialogContext.Context, submittedData); return Request.CreateResponse(HttpStatusCode.OK); } // 处理普通对话消息 await Conversation.SendAsync(activity, () => new RootDialog()); } else { HandleSystemMessage(activity); } return Request.CreateResponse(HttpStatusCode.OK); }
关键原理说明
当你调用PromptDialog.Choice后,Bot的对话栈会将当前步骤标记为"等待用户选择",所有后续消息都会被路由到这个步骤。如果消息不符合选择要求,Prompt会自动重试显示选择提示。通过提前捕获卡片提交的消息并结束当前等待步骤,就能避免这个问题,同时你依然可以使用context对象来收集和处理数据,和ShowInitOptions中的上下文保持一致。
内容的提问来源于stack exchange,提问作者Pradeep Patel
相关产品推荐
相关产品推荐

