Bot Framework中如何向Hero Card传递不显示的任务ID并取回
解决Bot Framework Hero Card隐藏传递任务ID的问题
嘿,我来帮你搞定这个需求!要实现“卡片不显示任务ID,但选中时后端能获取并存储”的效果,核心思路是把任务ID藏在卡片按钮的交互参数里,用户看不到,但后端能拿到。下面是具体的实现步骤和代码示例:
一、创建带隐藏任务ID的Hero Card
Hero Card的按钮支持PostBack类型——这种类型的按钮点击后,会把你设置的value参数悄悄发给后端,而用户在聊天界面只会看到按钮的标题,完全看不到任务ID。
假设你有一个任务列表,每个任务包含TaskId和TaskName,可以这样生成卡片:
// 示例任务列表 var tasks = new List<TaskItem> { new TaskItem { TaskId = "task_001", TaskName = "完成项目需求文档" }, new TaskItem { TaskId = "task_002", TaskName = "修复用户登录BUG" }, new TaskItem { TaskId = "task_003", TaskName = "部署测试环境" } }; // 批量生成Hero Card var heroCards = tasks.Select(task => new HeroCard { Title = task.TaskName, // 可以添加副标题、图片等其他展示内容 Subtitle = "点击下方按钮选择此任务", Buttons = new List<CardAction> { // 用PostBack类型按钮,把任务ID放到value里 new CardAction(ActionTypes.PostBack, title: "选择任务", value: task.TaskId) } }).ToList(); // 组装成轮播消息发送给用户 var carouselReply = MessageFactory.Carousel(heroCards); await turnContext.SendActivityAsync(carouselReply, cancellationToken);
二、后端捕获并存储任务ID
当用户点击卡片按钮后,Bot会收到一条PostBack类型的消息,你需要在消息处理逻辑中提取value字段的任务ID,然后存储到内存(比如对话状态、全局缓存等)。
1. 临时存储(当前对话回合有效)
如果只需要在当前回合使用这个ID,可以用TurnState:
protected override async Task OnMessageActivityAsync(ITurnContext<IMessageActivity> turnContext, CancellationToken cancellationToken) { // 检查是否是PostBack消息 if (turnContext.Activity.Value != null) { // 提取任务ID var selectedTaskId = turnContext.Activity.Value.ToString(); // 存储到TurnState,仅当前回合有效 turnContext.TurnState["SelectedTaskId"] = selectedTaskId; // 给用户反馈(不用显示ID) await turnContext.SendActivityAsync("已选中任务,后续将执行相关操作", cancellationToken: cancellationToken); // 这里可以直接调用API // await CallTaskApi(selectedTaskId); } else { await turnContext.SendActivityAsync("请通过卡片选择任务", cancellationToken: cancellationToken); } }
2. 持久存储(跨对话回合有效)
如果需要在后续对话中继续使用这个ID,建议用ConversationState(对话状态):
首先定义一个对话状态类:
public class ConversationData { public string SelectedTaskId { get; set; } }
然后在Bot的构造函数中注入ConversationState,并在消息处理中保存:
private readonly ConversationState _conversationState; private readonly IStatePropertyAccessor<ConversationData> _conversationDataAccessor; public YourBot(ConversationState conversationState) { _conversationState = conversationState; _conversationDataAccessor = _conversationState.CreateProperty<ConversationData>(nameof(ConversationData)); } protected override async Task OnMessageActivityAsync(ITurnContext<IMessageActivity> turnContext, CancellationToken cancellationToken) { if (turnContext.Activity.Value != null) { var selectedTaskId = turnContext.Activity.Value.ToString(); // 获取对话状态实例 var conversationData = await _conversationDataAccessor.GetAsync(turnContext, () => new ConversationData()); // 保存任务ID conversationData.SelectedTaskId = selectedTaskId; // 持久化到状态存储 await _conversationState.SaveChangesAsync(turnContext, false, cancellationToken); await turnContext.SendActivityAsync("任务已选中,后续操作将基于此任务执行", cancellationToken: cancellationToken); } }
三、后续使用任务ID
之后需要调用API时,直接从存储中取出ID即可:
// 从ConversationState中取出 var conversationData = await _conversationDataAccessor.GetAsync(turnContext, () => new ConversationData()); var taskId = conversationData.SelectedTaskId; // 调用API var apiResponse = await HttpClient.GetAsync($"https://your-api-url/tasks/{taskId}");
这样就完美实现了你的需求:卡片上看不到任务ID,用户选中后后端能安全获取并存储,后续随时调用~
内容的提问来源于stack exchange,提问作者user9463688
相关产品推荐
相关产品推荐

