相关文章推荐
快乐的板凳  ·  android - androidx ...·  1 年前    · 
千年单身的充电器  ·  中文信息·  1 年前    · 
有腹肌的黄花菜  ·  java - Error "A JNI ...·  1 年前    · 

可以使用自适应卡片和 Bot Framework 卡上的按钮从 Microsoft Teams 机器人调用任务模块,这些按钮是用于Microsoft 365 组的英雄、缩略图和连接器。 任务模块通常是比多对话步骤更好的用户体验。 跟踪机器人状态,并允许用户中断或取消序列。

调用任务模块有两种方法:

  • 新的调用消息 task/fetch :使用 invoke Bot Framework 卡的卡片操作 Action.Submit 自适应 卡片的卡片操作 ,以及 task/fetch ,任务模块(URL 或自适应卡)将从机器人动态提取。
  • 深层链接 URL:使用 任务模块的深层链接语法 ,可以分别使用 Bot Framework 卡片的 openUrl 卡片操作 Action.OpenUrl 自适应 卡片的卡片操作 。 使用深层链接 URL 时,任务模块 URL 或自适应卡片正文已知,以避免服务器相对于 task/fetch 往返。
  • 每个 url fallbackUrl 都必须实现 HTTPS 加密协议。

    下节提供有关使用 task/fetch 调用任务模块的详细信息。

    使用 调用任务模块 task/fetch

    invoke 卡片操作的 value 对象或 Action.Submit 已初始化,且当用户选择该按钮时,会向机器人发送一条 invoke 消息。 在对消息的 invoke HTTP 响应中,包装器对象中嵌入了 一个 TaskInfo 对象 ,Teams 使用该对象来显示任务模块。

    以下步骤使用 提供调用任务模块 task/fetch

  • 此图显示了 Bot Framework 主卡,其中包含 “购买 invoke 卡片”操作 type 属性的值是 task/fetch value 对象的其余部分可自行选择。

  • 机器人接收 invoke HTTP POST 消息。

  • 机器人将创建答复对象,并使用 HTTP 200 答复代码在 POST 答复正文中将其返回。 有关响应架构的详细信息,请参阅 有关任务/提交的讨论 。 以下代码提供了 HTTP 答复正文的示例,其中包含嵌入到包装器对象中的 TaskInfo 对象

    "task": { "type": "continue", "value": { "title": "Task module title", "height": 500, "width": "medium", "url": "https://contoso.com/msteams/taskmodules/newcustomer", "fallbackUrl": "https://contoso.com/msteams/taskmodules/newcustomer"

    task/fetch 事件及其针对机器人的响应类似于 microsoftTeams.tasks.startTask() Microsoft Teams JavaScript 客户端库中的 函数, (TeamsJS) 。

  • Microsoft Teams 显示任务模块。

    下节提供有关提交任务模块结果的详细信息。

    提交任务模块的结果

    当用户完成任务模块后,将结果提交回机器人时与使用选项卡的方式类似。 有关详细信息,请参阅 提交任务模块的结果示例 。 存在一些差异,见如下所示:

  • HTML 或 JavaScript,即 TaskInfo.url :验证用户输入的内容后,出于可读性目的,调用 microsoftTeams.tasks.submitTask() 下文中引用的 submitTask() 函数。 如果希望 Teams 关闭任务模块,可以调用不带任何参数的 submitTask() ,但必须将对象或字符串传递给 submitHandler 。 将其作为第一个参数 result 传递。 Teams 调用 submitHandler err null result 是传递给 submitTask() 的对象或字符串。 如果调用带 result 参数的 submitTask() ,则必须传递 appId appId 字符串的数组。 这允许 Teams 验证发送结果的应用是否与调用任务模块的相同。 机器人收到一条 task/submit 消息,包括 result 。 有关详细信息,请参阅 task/fetch task/submit 消息的有效负载
  • 自适应卡片是 TaskInfo.card :当用户选择任何 Action.Submit 按钮时,用户填写的自适应卡片正文将通过 task/submit 消息发送到机器人。
  • 下一部分详细介绍了如何响应 task/submit 消息。

    响应 task/submit 消息

    当用户完成从机器人调用的任务模块后,机器人始终会收到一条 task/submit invoke 消息。 答复 task/submit 消息时有多个选项,见如下所示:

    HTTP 正文答复

    将自适应卡片链接到序列中是一种高级应用场景。 Node.js 示例应用支持此操作。 有关详细信息,请参阅 Microsoft Teams 任务模块 Node.js

    下节提供有关 task/fetch task/submit 消息有效负载的详细信息。

    task/submit 消息的有效 task/fetch 负载

    本节定义机器人收到 task/fetch task/submit Bot Framework Activity 对象时收到的内容架构。 下表提供了 task/fetch task/submit 消息有效负载的属性:

    value 是开发人员定义的有效负载。 value 对象的结构与从 Teams 发送的结构相同。 但是,在这种情况下,情况会有所不同。 它需要支持动态提取,即从机器人框架 task/fetch ,也就是 value 和自适应卡片 Action.Submit 操作,即 data 。 除了 value data 中包含的内容外,还需要一种 Teams context 与机器人通信的方法。

    将“值”和“数据”组合到父对象中:

    {
    “context”: {
    “theme”: “default” |“dark” |“contrast”,
    },
    “data”:[Bot Framework 卡片中的值字段] |[自适应卡片中的数据字段]
    }

    下节提供在 Node.js 中接收和答复 task/fetch task/submit 调用消息的示例。

    以下选项卡在 Node.js 和 C# 中提供 task/fetch task/submit 调用消息:

    Node.js
    handleTeamsTaskModuleFetch(context, taskModuleRequest) {
        // Called when the user selects an options from the displayed HeroCard or
        // AdaptiveCard.  The result is the action to perform.
        const cardTaskFetchValue = taskModuleRequest.data.data;
        var taskInfo = {}; // TaskModuleTaskInfo
        if (cardTaskFetchValue === TaskModuleIds.YouTube) {
            // Display the YouTube.html page
            taskInfo.url = taskInfo.fallbackUrl = this.baseUrl + '/' + TaskModuleIds.YouTube + '.html';
            this.setTaskInfo(taskInfo, TaskModuleUIConstants.YouTube);
        } else if (cardTaskFetchValue === TaskModuleIds.CustomForm) {
            // Display the CustomForm.html page, and post the form data back via
            // handleTeamsTaskModuleSubmit.
            taskInfo.url = taskInfo.fallbackUrl = this.baseUrl + '/' + TaskModuleIds.CustomForm + '.html';
            this.setTaskInfo(taskInfo, TaskModuleUIConstants.CustomForm);
        } else if (cardTaskFetchValue === TaskModuleIds.AdaptiveCard) {
            // Display an AdaptiveCard to prompt user for text, and post it back via
            // handleTeamsTaskModuleSubmit.
            taskInfo.card = this.createAdaptiveCardAttachment();
            this.setTaskInfo(taskInfo, TaskModuleUIConstants.AdaptiveCard);
        return TaskModuleResponseFactory.toTaskModuleResponse(taskInfo);
    async handleTeamsTaskModuleSubmit(context, taskModuleRequest) {
        // Called when data is being returned from the selected option (see `handleTeamsTaskModuleFetch').
        // Echo the users input back.  In a production bot, this is where you'd add behavior in
        // response to the input.
        await context.sendActivity(MessageFactory.text('handleTeamsTaskModuleSubmit: ' + JSON.stringify(taskModuleRequest.data)));
        // Return TaskModuleResponse
        return {
            // TaskModuleMessageResponse
            task: {
                type: 'message',
                value: 'Thanks!'
    setTaskInfo(taskInfo, uiSettings) {
        taskInfo.height = uiSettings.height;
        taskInfo.width = uiSettings.width;
        taskInfo.title = uiSettings.title;
    
    protected override Task<TaskModuleResponse> OnTeamsTaskModuleFetchAsync(ITurnContext<IInvokeActivity> turnContext, TaskModuleRequest taskModuleRequest, CancellationToken cancellationToken)
        var asJobject = JObject.FromObject(taskModuleRequest.Data);
        var value = asJobject.ToObject<CardTaskFetchValue<string>>()?.Data;
        var taskInfo = new TaskModuleTaskInfo();
        switch (value)
            case TaskModuleIds.YouTube:
                taskInfo.Url = taskInfo.FallbackUrl = _baseUrl + "/" + TaskModuleIds.YouTube;
                SetTaskInfo(taskInfo, TaskModuleUIConstants.YouTube);
                break;
            case TaskModuleIds.CustomForm:
                taskInfo.Url = taskInfo.FallbackUrl = _baseUrl + "/" + TaskModuleIds.CustomForm;
                SetTaskInfo(taskInfo, TaskModuleUIConstants.CustomForm);
                break;
            case TaskModuleIds.AdaptiveCard:
                taskInfo.Card = CreateAdaptiveCardAttachment();
                SetTaskInfo(taskInfo, TaskModuleUIConstants.AdaptiveCard);
                break;
            default:
                break;
        return Task.FromResult(taskInfo.ToTaskModuleResponse());
    protected override async Task<TaskModuleResponse> OnTeamsTaskModuleSubmitAsync(ITurnContext<IInvokeActivity> turnContext, TaskModuleRequest taskModuleRequest, CancellationToken cancellationToken)
        var reply = MessageFactory.Text("OnTeamsTaskModuleSubmitAsync Value: " + JsonConvert.SerializeObject(taskModuleRequest));
        await turnContext.SendActivityAsync(reply, cancellationToken);
        return TaskModuleResponseFactory.CreateResponse("Thanks!");
    private static void SetTaskInfo(TaskModuleTaskInfo taskInfo, UISettings uIConstants)
        taskInfo.Height = uIConstants.Height;
        taskInfo.Width = uIConstants.Width;
        taskInfo.Title = uIConstants.Title.ToString();
    

    Bot Framework 卡片操作与自适应卡片操作。提交操作

    Bot Framework 卡片操作的架构不同于自适应卡片 Action.Submit 操作,调用任务模块的方式也不同。 中的 dataAction.Submit 对象包含对象 msteams ,因此它不会干扰卡片中的其他属性。 下表显示了每个卡片操作的示例:

    Bot Framework 卡片操作 自适应卡片 Action.Submit 操作