You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

基于Microsoft Bot Framework实现应用列表展示及详情查询功能求助

基于Microsoft Bot Framework的应用列表与详情实现方案

针对你的需求,以下是基于Bot Framework SDK v4的具体实现步骤和代码示例,适配基础开发者的技术栈:

核心流程梳理

  1. 通过瀑布对话收集用户账号、出生日期信息
  2. 调用你的数据API获取应用列表
  3. 用自适应卡片渲染带可交互入口的应用列表(普通Markdown链接无法触发机器人逻辑,自适应卡片的提交按钮可携带参数触发后续操作)
  4. 捕获用户点击事件,根据携带的applicationID调用API获取详情并返回

代码示例(C#)

1. 基础结构与对话注册

using Microsoft.Bot.Builder;
using Microsoft.Bot.Builder.Dialogs;
using Microsoft.Bot.Schema;
using Newtonsoft.Json;
using System.Collections.Generic;
using System.Net.Http;
using System.Threading;
using System.Threading.Tasks;

public class ApplicationBot : ActivityHandler
{
    private readonly ConversationState _conversationState;
    private readonly HttpClient _httpClient;
    private readonly DialogSet _dialogSet;

    public ApplicationBot(ConversationState conversationState, HttpClient httpClient)
    {
        _conversationState = conversationState;
        _httpClient = httpClient;
        _dialogSet = new DialogSet(_conversationState.CreateProperty<DialogState>(nameof(DialogState)));
        _dialogSet.Add(new WaterfallDialog("InfoCollection", new WaterfallStep[]
        {
            AskAccountStepAsync,
            AskBirthDateStepAsync,
            FetchAppsStepAsync
        }));
        // 注册文本提示器
        _dialogSet.Add(new TextPrompt("AccountPrompt"));
        _dialogSet.Add(new TextPrompt("BirthDatePrompt"));
    }

    protected override async Task OnMessageActivityAsync(ITurnContext<IMessageActivity> turnContext, CancellationToken cancellationToken)
    {
        var conversationData = await _conversationState.CreateProperty<ConversationData>(nameof(ConversationData))
            .GetAsync(turnContext, () => new ConversationData(), cancellationToken);

        // 处理应用详情请求
        if (turnContext.Activity.Value != null)
        {
            var submitData = JsonConvert.DeserializeObject<AppSubmitData>(turnContext.Activity.Value.ToString());
            if (!string.IsNullOrEmpty(submitData.ApplicationId))
            {
                await FetchAppDetailsAsync(turnContext, submitData.ApplicationId, cancellationToken);
                return;
            }
        }

        // 未收集信息则启动对话
        var dialogContext = await _dialogSet.CreateContextAsync(turnContext, cancellationToken);
        if (dialogContext.Status == DialogTurnStatus.Empty)
        {
            await dialogContext.BeginDialogAsync("InfoCollection", null, cancellationToken);
        }
        else
        {
            await dialogContext.ContinueDialogAsync(cancellationToken);
        }

        await _conversationState.SaveChangesAsync(turnContext, false, cancellationToken);
    }
}

2. 瀑布对话步骤实现

// 询问账号
private async Task<DialogTurnResult> AskAccountStepAsync(WaterfallStepContext stepContext, CancellationToken cancellationToken)
{
    return await stepContext.PromptAsync("AccountPrompt",
        new PromptOptions { Prompt = MessageFactory.Text("请提供您的账号") }, cancellationToken);
}

// 询问出生日期
private async Task<DialogTurnResult> AskBirthDateStepAsync(WaterfallStepContext stepContext, CancellationToken cancellationToken)
{
    stepContext.Values["Account"] = stepContext.Result.ToString();
    return await stepContext.PromptAsync("BirthDatePrompt",
        new PromptOptions { Prompt = MessageFactory.Text("请提供您的出生日期(格式:YYYY-MM-DD)") }, cancellationToken);
}

// 获取并渲染应用列表
private async Task<DialogTurnResult> FetchAppsStepAsync(WaterfallStepContext stepContext, CancellationToken cancellationToken)
{
    var account = stepContext.Values["Account"].ToString();
    var birthDate = stepContext.Result.ToString();

    // 调用你的数据API(替换为实际地址)
    var response = await _httpClient.GetAsync($"https://your-api-domain/apps?account={account}&birthDate={birthDate}");
    response.EnsureSuccessStatusCode();
    var apps = await response.Content.ReadFromJsonAsync<List<Application>>();

    // 构建自适应卡片
    var card = new AdaptiveCard(new AdaptiveSchemaVersion(1, 0))
    {
        Body = new List<AdaptiveElement>
        {
            new AdaptiveTextBlock { Text = "您的应用列表", Size = AdaptiveTextSize.Large, Weight = AdaptiveTextWeight.Bold }
        },
        Actions = new List<AdaptiveAction>()
    };

    foreach (var app in apps)
    {
        card.Body.Add(new AdaptiveTextBlock { Text = $"应用ID: {app.ApplicationId}", Size = AdaptiveTextSize.Medium });
        card.Body.Add(new AdaptiveTextBlock { Text = $"状态: {app.Status}", Margin = AdaptiveMargin.Small });
        // 添加详情按钮,携带applicationID参数
        card.Actions.Add(new AdaptiveSubmitAction
        {
            Title = "查看详情",
            Data = new { ApplicationId = app.ApplicationId }
        });
        card.Body.Add(new AdaptiveHorizontalRule());
    }

    // 发送卡片
    await stepContext.Context.SendActivityAsync(MessageFactory.Attachment(new Attachment
    {
        ContentType = AdaptiveCard.ContentType,
        Content = card
    }), cancellationToken);

    // 标记信息已收集
    var conversationData = await _conversationState.CreateProperty<ConversationData>(nameof(ConversationData))
        .GetAsync(stepContext.Context, () => new ConversationData(), cancellationToken);
    conversationData.IsInfoCollected = true;

    return await stepContext.EndDialogAsync(cancellationToken);
}

3. 应用详情获取逻辑

private async Task FetchAppDetailsAsync(ITurnContext<IMessageActivity> turnContext, string appId, CancellationToken cancellationToken)
{
    // 调用详情API(替换为实际地址)
    var response = await _httpClient.GetAsync($"https://your-api-domain/apps/details?appId={appId}");
    response.EnsureSuccessStatusCode();
    var details = await response.Content.ReadFromJsonAsync<ApplicationDetails>();

    // 构造详情消息
    var detailMsg = $"应用详情:\n" +
                   $"应用ID: {details.ApplicationId}\n" +
                   $"申请日期: {details.ApplicationDate:yyyy-MM-dd}\n" +
                   $"状态: {details.Status}\n" +
                   $"备注: {details.Remarks ?? "无"}";

    await turnContext.SendActivityAsync(detailMsg, cancellationToken: cancellationToken);
}

// 辅助实体类
public class ConversationData
{
    public bool IsInfoCollected { get; set; } = false;
}

public class Application
{
    public string Id { get; set; }
    // 适配API返回的拼写错误(applicaitonID)
    [JsonProperty("applicaitonID")]
    public string ApplicationId { get; set; }
    public string Status { get; set; }
}

public class ApplicationDetails
{
    public string ApplicationId { get; set; }
    public System.DateTime ApplicationDate { get; set; }
    public string Status { get; set; }
    public string Remarks { get; set; }
}

public class AppSubmitData
{
    public string ApplicationId { get; set; }
}

关键注意事项

  • 自适应卡片必要性:普通Markdown链接仅能跳转外部网页,无法触发机器人逻辑;AdaptiveSubmitAction可携带参数直接触发后端处理,是实现需求的核心。
  • API字段映射:你的API返回中applicaitonID存在拼写错误(应为applicationID),需通过JsonProperty特性做字段映射,避免序列化失败。
  • 错误处理:示例省略了API调用失败的分支,实际开发中需添加try-catch块,返回友好提示(如“暂时无法获取数据,请稍后重试”)。
  • 参数验证:收集用户信息时需添加格式校验(如出生日期合法性),减少无效API调用。

开发建议

  1. 使用ConversationState管理对话状态,避免重复询问用户信息。
  2. 在不同渠道(Web Chat、Teams)测试卡片显示效果,确保兼容性。
  3. 添加日志记录API请求/响应,便于排查问题。
  4. 若需支持多轮对话,可扩展对话逻辑实现信息补全或修改。

内容的提问来源于stack exchange,提问作者TechTurtle

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.03 07:32:03