创建和发送对话框
重要
本部分中的代码示例基于 v4.6 及更高版本的 Bot Framework SDK。 如果要查找早期版本的文档,请参阅文档的 Resources 文件夹中 的消息扩展 - v3 SDK 部分。
可以使用自适应卡片或嵌入式 Web 视图 (TeamsJS v1.x) 中创建称为任务模块的模式对话框。 若要创建对话,必须执行称为初始调用请求的过程。 本文档介绍从 1:1 聊天调用对话时的初始调用请求、有效负载活动属性、群组聊天、频道 (新发布) 、频道 (线程) 答复以及命令框。
注意
如果未使用应用清单中定义的参数填充对话框,则必须使用自适应卡片或嵌入的 Web 视图为用户创建对话框。
初始调用请求
在初始调用请求的过程中,服务接收 composeExtensions/fetchTask
类型的 Activity
对象,并且必须使用包含自适应卡片或嵌入 Web 视图 URL 的 task
对象进行响应。 除标准机器人活动属性,初始调用有效负载还包含以下请求元数据:
属性名称 | 用途 |
---|---|
type |
请求类型。 它必须为 invoke 。 |
name |
颁发给服务的命令类型。 它必须为 composeExtension/fetchTask 。 |
from.id |
发送请求的用户 ID。 |
from.name |
发送请求的用户名。 |
from.aadObjectId |
Microsoft发送请求的用户的 Entra 对象 ID。 |
channelData.tenant.id |
Microsoft Entra 租户 ID。 |
channelData.channel.id |
频道 ID(如果请求是在频道中发出)。 |
channelData.team.id |
团队 ID(如果请求是在频道中发出)。 |
value.commandId |
包含已调用命令的 ID。 |
value.commandContext |
触发事件的上下文。 它必须为 compose 。 |
value.context.theme |
用户的客户端主题,对于嵌入式 Web 视图格式设置非常有用。 它必须为 default 、contrast 或 dark 。 |
示例
以下示例提供了初始调用请求的代码:
{
"type": "invoke",
"id": "f:bc319b1d-571a-194d-9ffb-11d7ab37c9ff",
"from": {
"id": "29:1aBjVi5MwCFfhPIV03E5uDdfpBFXp_2Yz-sjrvVg12oavg96cqpE_DiMhOpmN9zHeZpYbJcuUEKuSDy2AYWPz1A",
"name": "Olo Brockhouse",
"aadObjectId": "b130c271-d2eb-45f9-83ab-9eb3fe3788bc"
}
"channelData": {
"tenant": {
"id": "0d9b645f-597b-41f0-a2a3-ef103fbd91bb"
},
"source": {
"name": "compose"
}
},
"value": {
"commandId": "Test",
"commandContext": "compose",
"requestId": "fe50f49e5c74440bb2ebf07f49e9553c",
"context": {
"theme": "default"
}
},
"name": "composeExtension/fetchTask"
从 1:1 聊天调用对话时的有效负载活动属性
从 1:1 聊天调用对话时的有效负载活动属性如下所示:
属性名称 | 用途 |
---|---|
type |
请求类型。 它必须为 invoke 。 |
name |
颁发给服务的命令类型。 它必须为 composeExtension/fetchTask 。 |
from.id |
发送请求的用户 ID。 |
from.name |
发送请求的用户名。 |
from.aadObjectId |
Microsoft发送请求的用户的 Entra 对象 ID。 |
channelData.tenant.id |
Microsoft Entra 租户 ID。 |
channelData.source.name |
从中调用对话框的源名称。 |
ChannelData.legacy. replyToId |
获取或设置此消息作为所答复消息的 ID。 |
value.commandId |
包含已调用命令的 ID。 |
value.commandContext |
触发事件的上下文。 它必须为 compose 。 |
value.context.theme |
用户的客户端主题,对于嵌入式 Web 视图格式设置非常有用。 它必须为 default 、contrast 或 dark 。 |
示例
以下示例中提供了从 1:1 聊天调用对话时的有效负载活动属性:
{
"type": "invoke",
"id": "f:bc319b1d-571a-194d-9ffb-11d7ab37c9ff",
"from": {
"id": "29:1aBjVi5MwCFfhPIV03E5uDdfpBFXp_2Yz-sjrvVg12oavg96cqpE_DiMhOpmN9zHeZpYbJcuUEKuSDy2AYWPz1A",
"name": "Olo Brockhouse",
"aadObjectId": "b130c271-d2eb-45f9-83ab-9eb3fe3788bc"
}
"channelData": {
"tenant": {
"id": "0d9b645f-597b-41f0-a2a3-ef103fbd91bb"
},
"source": {
"name": "compose"
}
},
"value": {
"commandId": "Test",
"commandContext": "compose",
"requestId": "fe50f49e5c74440bb2ebf07f49e9553c",
"context": {
"theme": "default"
}
},
"name": "composeExtension/fetchTask"
}
从群组聊天调用对话时的有效负载活动属性
从群聊调用对话时的有效负载活动属性如下所示:
属性名称 | 用途 |
---|---|
type |
请求类型。 它必须为 invoke 。 |
name |
颁发给服务的命令类型。 它必须为 composeExtension/fetchTask 。 |
from.id |
发送请求的用户 ID。 |
from.name |
发送请求的用户名。 |
from.aadObjectId |
Microsoft发送请求的用户的 Entra 对象 ID。 |
channelData.tenant.id |
Microsoft Entra 租户 ID。 |
channelData.source.name |
从中调用对话框的源名称。 |
ChannelData.legacy. replyToId |
获取或设置此消息作为所答复消息的 ID。 |
value.commandId |
包含已调用命令的 ID。 |
value.commandContext |
触发事件的上下文。 它必须为 compose 。 |
value.context.theme |
用户的客户端主题,对于嵌入式 Web 视图格式设置非常有用。 它必须为 default 、contrast 或 dark 。 |
示例
以下示例中提供了从群聊调用对话时的有效负载活动属性:
{
"type": "invoke",
"id": "f:bf72031f-a17e-f99c-48dc-5c0714950d87",
"from": {
"id": "29:1aBjVi5MwCFfhPIV03E5uDdfpBFXp_2Yz-sjrvVg12oavg96cqpE_DiMhOpmN9zHeZpYbJcuUEKuSDy2AYWPz1A",
"name": "Olo Brockhouse",
"aadObjectId": "b130c271-d2eb-45f9-83ab-9eb3fe3788bc"
},
"conversation": {
"isGroup": true,
"conversationType": "groupChat",
"id": "19:d77be72390a1416e9644261e9064fa00@thread.skype",
"tenantId": "0d9b645f-597b-41f0-a2a3-ef103fbd91bb"
},
"channelData": {
"tenant": {
"id": "0d9b645f-597b-41f0-a2a3-ef103fbd91bb"
},
"source": {
"name": "compose"
}
},
"value": {
"commandId": "Test",
"commandContext": "compose",
"requestId": "213167a1e3b6428b93e186ea5407c759",
"context": {
"theme": "default"
}
},
"name": "composeExtension/fetchTask"
}
从会议聊天调用对话时的有效负载活动属性
以下示例中提供了从会议聊天调用对话时的有效负载活动属性:
{
"type": "invoke",
"id": "f:4d271f11-4eed-622f-e820-6d82bf91692f",
"channelId": "msteams",
"from": {
"id": "29:1yLsdbTM1UjxqqD8cjduNUCI1jm8xZaH3lx9u5JQ04t2bknuTCkP45TXdfROTOWk1LzN1AqTgFZUEqHIVGn_qUA",
"name": "MOD Administrator",
"aadObjectId": "ef16aa89-5b26-4a2c-aebb-761b551577c0"
},
"conversation": {
"tenantId": "c9f9aafd-64ac-4f38-8e05-12feba3fb090",
"id": "19:meeting_NTk4ZDY4ZmYtOWEzZS00OTRkLThhY2EtZmUzZmUzMDQyM2M0@thread.v2",
"name": "Test meeting"
},
"channelData": {
"tenant": {
"id": "c9f9aafd-64ac-4f38-8e05-12feba3fb090"
},
"source": {
"name": "compose"
},
"meeting": {
"id": "MCMxOTptZWV0aW5nX05UazRaRFk0Wm1ZdE9XRXpaUzAwT1RSa0xUaGhZMkV0Wm1VelptVXpNRFF5TTJNMEB0aHJlYWQudjIjMA=="
}
},
"value": {
"commandId": "Test",
"commandContext": "compose",
"requestId": "c46a6b53573f42b5bc801716e5ccc960",
"context": {
"theme": "default"
}
},
"name": "composeExtension/fetchTask",
}
从频道 (新发布) 调用对话时的有效负载活动属性
从频道 (新发布) 调用对话时的有效负载活动属性如下所示:
属性名称 | 用途 |
---|---|
type |
请求类型。 它必须为 invoke 。 |
name |
颁发给服务的命令类型。 它必须为 composeExtension/fetchTask 。 |
from.id |
发送请求的用户 ID。 |
from.name |
发送请求的用户名。 |
from.aadObjectId |
Microsoft发送请求的用户的 Entra 对象 ID。 |
channelData.tenant.id |
Microsoft Entra 租户 ID。 |
channelData.channel.id |
频道 ID(如果请求是在频道中发出)。 |
channelData.team.id |
团队 ID(如果请求是在频道中发出)。 |
channelData.source.name |
从中调用对话框的源名称。 |
ChannelData.legacy. replyToId |
获取或设置此消息作为所答复消息的 ID。 |
value.commandId |
包含已调用命令的 ID。 |
value.commandContext |
触发事件的上下文。 它必须为 compose 。 |
value.context.theme |
用户的客户端主题,对于嵌入式 Web 视图格式设置非常有用。 它必须为 default 、contrast 或 dark 。 |
示例
以下示例中提供了从通道 (新发布) 调用对话时的有效负载活动属性:
{
"type": "invoke",
"id": "f:a5fbb109-c989-c449-ee83-71ac99919d4b",
"from": {
"id": "29:1aBjVi5MwCFfhPIV03E5uDdfpBFXp_2Yz-sjrvVg12oavg96cqpE_DiMhOpmN9zHeZpYbJcuUEKuSDy2AYWPz1A",
"name": "Olo Brockhouse",
"aadObjectId": "b130c271-d2eb-45f9-83ab-9eb3fe3788bc"
},
"conversation": {
"isGroup": true,
"conversationType": "channel",
"id": "19:6decf54d86d945e4b3924b63a9161a78@thread.skype",
"name": "parsable",
"tenantId": "0d9b645f-597b-41f0-a2a3-ef103fbd91bb"
},
"channelData": {
"channel": {
"id": "19:6decf54d86d945e4b3924b63a9161a78@thread.skype"
},
"team": {
"id": "19:acca514e83cb497e960e0b014d405336@thread.skype"
},
"tenant": {
"id": "0d9b645f-597b-41f0-a2a3-ef103fbd91bb"
},
"source": {
"name": "compose"
}
},
"value": {
"commandId": "Test",
"commandContext": "compose",
"requestId": "5336640edc7748b28ce2df43f5b45963",
"context": {
"theme": "default"
}
},
"name": "composeExtension/fetchTask"
}
从通道调用对话时的有效负载活动属性 (答复线程)
从通道调用对话时的有效负载活动属性 (答复线程) 如下所示:
属性名称 | 用途 |
---|---|
type |
请求类型。 它必须为 invoke 。 |
name |
颁发给服务的命令类型。 它必须为 composeExtension/fetchTask 。 |
from.id |
发送请求的用户 ID。 |
from.name |
发送请求的用户名。 |
from.aadObjectId |
Microsoft发送请求的用户的 Entra 对象 ID。 |
channelData.tenant.id |
Microsoft Entra 租户 ID。 |
channelData.channel.id |
频道 ID(如果请求是在频道中发出)。 |
channelData.team.id |
团队 ID(如果请求是在频道中发出)。 |
channelData.source.name |
从中调用对话框的源名称。 |
ChannelData.legacy. replyToId |
获取或设置此消息作为所答复消息的 ID。 |
value.commandId |
包含已调用命令的 ID。 |
value.commandContext |
触发事件的上下文。 它必须为 compose 。 |
value.context.theme |
用户的客户端主题,对于嵌入式 Web 视图格式设置非常有用。 它必须为 default 、contrast 或 dark 。 |
示例
以下示例中提供了从通道调用对话 (回复线程) 时的有效负载活动属性:
{
"type": "invoke",
"id": "f:19ccc884-c792-35ef-2f40-d0ff43dcca71",
"from": {
"id": "29:1aBjVi5MwCFfhPIV03E5uDdfpBFXp_2Yz-sjrvVg12oavg96cqpE_DiMhOpmN9zHeZpYbJcuUEKuSDy2AYWPz1A",
"name": "Olo Brockhouse",
"aadObjectId": "b130c271-d2eb-45f9-83ab-9eb3fe3788bc"
},
"conversation": {
"isGroup": true,
"conversationType": "channel",
"id": "19:6decf54d86d945e4b3924b63a9161a78@thread.skype;messageid=1611060744833",
"name": "parsable",
"tenantId": "0d9b645f-597b-41f0-a2a3-ef103fbd91bb"
},
"channelData": {
"channel": {
"id": "19:6decf54d86d945e4b3924b63a9161a78@thread.skype"
},
"team": {
"id": "19:acca514e83cb497e960e0b014d405336@thread.skype"
},
"tenant": {
"id": "0d9b645f-597b-41f0-a2a3-ef103fbd91bb"
},
"source": {
"name": "compose"
}
},
"value": {
"commandId": "TEst",
"commandContext": "message",
"requestId": "7f7d22efe5414818becebcec649a7912",
"messagePayload": {
"linkToMessage": "https://teams.microsoft.com/l/message/19:6decf54d86d945e4b3924b63a9161a78@thread.skype/1611060744833",
"id": "1611060744833",
"replyToId": null,
"createdDateTime": "2021-01-19T12:52:24.833Z",
"lastModifiedDateTime": null,
"deleted": false,
"summary": null,
"importance": "normal",
"locale": "en-us",
"body": {
"contentType": "html",
"content": "<div><div><at id=\"0\">Testing outgoing Webhook-Nikitha</at> - Hi</div>\n</div>"
},
"from": {
"device": null,
"conversation": null,
"user": {
"userIdentityType": "aadUser",
"id": "b130c271-d2eb-45f9-83ab-9eb3fe3788bc",
"displayName": "Olo Brockhouse"
},
"application": null
},
"reactions": [],
"mentions": [
{
"id": 0,
"mentionText": "Testing outgoing Webhook-Nikitha",
"mentioned": {
"device": null,
"conversation": null,
"user": null,
"application": {
"applicationIdentityType": "webhook",
"id": "b8c1c68c-e290-4bdd-81c3-266f310751dc",
"displayName": "Testing outgoing Webhook-Nikitha"
}
}
}
],
"attachments": []
},
"context": {
"theme": "default"
}
},
"name": "composeExtension/fetchTask"
}
从命令框中调用对话框时的有效负载活动属性
从命令框中调用对话框时的有效负载活动属性如下所示:
属性名称 | 用途 |
---|---|
type |
请求类型。 它必须为 invoke 。 |
name |
颁发给服务的命令类型。 它必须为 composeExtension/fetchTask 。 |
from.id |
发送请求的用户 ID。 |
from.name |
发送请求的用户名。 |
from.aadObjectId |
Microsoft发送请求的用户的 Entra 对象 ID。 |
channelData.tenant.id |
Microsoft Entra 租户 ID。 |
channelData.source.name |
从中调用对话框的源名称。 |
value.commandId |
包含已调用命令的 ID。 |
value.commandContext |
触发事件的上下文。 它必须为 compose 。 |
value.context.theme |
用户的客户端主题,对于嵌入式 Web 视图格式设置非常有用。 它必须为 default 、contrast 或 dark 。 |
示例
以下示例中提供了从命令框调用对话框时的有效负载活动属性:
{
"type": "invoke",
"id": "f:172560f1-95f9-3189-edb2-b7612cd1a3cd",
"id": "29:1aBjVi5MwCFfhPIV03E5uDdfpBFXp_2Yz-sjrvVg12oavg96cqpE_DiMhOpmN9zHeZpYbJcuUEKuSDy2AYWPz1A",
"name": "Olo Brockhouse",
"aadObjectId": "b130c271-d2eb-45f9-83ab-9eb3fe3788bc"
},
"conversation": {
"isGroup": true,
"conversationType": "channel",
"id": "19:6decf54d86d945e4b3924b63a9161a78@thread.skype",
"name": "parsable",
"tenantId": "0d9b645f-597b-41f0-a2a3-ef103fbd91bb"
},
"channelData": {
"channel": {
"id": "19:6decf54d86d945e4b3924b63a9161a78@thread.skype"
},
"team": {
"id": "19:acca514e83cb497e960e0b014d405336@thread.skype"
},
"tenant": {
"id": "0d9b645f-597b-41f0-a2a3-ef103fbd91bb"
},
"source": {
"name": "compose"
}
},
"value": {
"commandId": "TEst",
"commandContext": "compose",
"requestId": "d2ce690cdc2b4920a538e75882610a30",
"context": {
"theme": "default"
}
},
"name": "composeExtension/fetchTask"
}
示例
下面的代码部分是 fetchTask
请求的示例:
protected override async Task<MessagingExtensionActionResponse> OnTeamsMessagingExtensionFetchTaskAsync(ITurnContext<IInvokeActivity> turnContext, MessagingExtensionAction action, CancellationToken cancellationToken)
{
//handle fetch task
}
来自消息的初始调用请求
从消息调用机器人时, value
初始调用请求中的 对象必须包含从中调用消息扩展的消息的详细信息。 这些 reactions
和 mentions
数组是可选的,如果原始消息中没有反应或提及,则它们不存在。
以下部分是 value
对象的示例:
protected override async Task<MessagingExtensionActionResponse> OnTeamsMessagingExtensionFetchTaskAsync(ITurnContext<IInvokeActivity> turnContext, MessagingExtensionAction action, CancellationToken cancellationToken)
{
var messageText = action.MessagePayload.Body.Content;
var fromId = action.MessagePayload.From.User.Id;
//finish handling the fetchTask
}
响应 fetchTask
使用包含具有自适应卡片或 Web URL 的 taskInfo
对象或简单字符串消息的 task
对象响应调用请求。
属性名称 | 用途 |
---|---|
type |
可以是 continue 用于呈现窗体,也可以 message 是用于简单弹出窗口。 |
value |
对于表单可为 taskInfo ,或对于消息为 string 。 |
taskInfo 对象的架构为:
属性名称 | 用途 |
---|---|
title |
对话框的标题。 |
height |
它必须是整数(以像素为单位)或small 、medium 、large 。 |
width |
它必须是整数(以像素为单位)或small 、medium 、large 。 |
card |
如果使用一个) ,则定义表单的自适应卡片 (。 |
url |
要作为嵌入式 Web 视图在对话框内打开的 URL。 |
fallbackUrl |
如果客户端不支持对话框功能,则会在浏览器选项卡中打开此 URL。 |
使用自适应卡片响应 fetchTask
使用自适应卡片时,必须使用包含自适应卡片的对象value
进行响应task
。
示例
以下代码部分是使用自适应卡进行响应的示例 fetchTask
:
除了 Bot Framework SDK 之外,此示例还使用 AdaptiveCards NuGet 包。
protected override async Task<MessagingExtensionActionResponse> OnTeamsMessagingExtensionFetchTaskAsync(ITurnContext<IInvokeActivity> turnContext, MessagingExtensionAction action, CancellationToken cancellationToken)
{
string placeholder = "Not invoked from message";
if (action.MessagePayload != null)
{
var messageText = action.MessagePayload.Body.Content;
var fromId = action.MessagePayload.From.User.Id;
placeholder = "Invoked from message";
}
var response = new MessagingExtensionActionResponse()
{
Task = new TaskModuleContinueResponse()
{
Value = new TaskModuleTaskInfo()
{
Height = "small",
Width = "small",
Title = "Example dialog",
Card = new Attachment()
{
ContentType = AdaptiveCard.ContentType,
Content = new AdaptiveCard("1.0")
{
Body = new List<AdaptiveElement>()
{
new AdaptiveTextInput() { Id = "FormField1", Placeholder = placeholder},
new AdaptiveTextInput() { Id = "FormField2", Placeholder = "FormField2"},
new AdaptiveTextInput() { Id = "FormField3", Placeholder = "FormField3"},
},
Actions = new List<AdaptiveAction>()
{
new AdaptiveSubmitAction()
{
Type = AdaptiveSubmitAction.TypeName,
Title = "Submit",
},
},
},
},
},
},
};
return response;
}
使用嵌入的 Web 视图创建对话框
使用嵌入式 Web 视图时,必须使用包含要加载 Web 窗体的 URL value
对象响应 task
对象。 要加载的任何 URL 的域必须包含在 validDomains
应用清单的数组中。 有关生成嵌入式 Web 视图的详细信息,请参阅 对话框文档。
protected override async Task<MessagingExtensionActionResponse> OnTeamsMessagingExtensionFetchTaskAsync(ITurnContext<IInvokeActivity> turnContext, MessagingExtensionAction action, CancellationToken cancellationToken)
{
string placeholder = "Not invoked from message";
if (action.MessagePayload != null)
{
var messageText = action.MessagePayload.Body.Content;
var fromId = action.MessagePayload.From.User.Id;
placeholder = "Invoked from message";
}
var response = new MessagingExtensionActionResponse()
{
Task = new TaskModuleContinueResponse()
{
Value = new TaskModuleTaskInfo()
{
Height = "small",
Width = "small",
Title = "Example dialog",
Url = "https://contoso.com/msteams/taskmodules/newcustomer",
},
},
},
};
return response;
}
请求安装对话机器人
如果应用包含对话机器人,请在聊天中安装机器人,然后加载对话。 机器人可用于获取对话的其他上下文。 此方案的一个示例是获取花名册以填充人员选取器控件或团队中的频道列表。
消息扩展收到 composeExtensions/fetchTask
调用时,请检查机器人是否安装在当前上下文中以加快流。 例如,使用获取名册调用检查流。 如果未安装机器人,请返回自适应卡片,其中包含请求用户安装机器人的操作。 用户必须有权在该位置安装应用以进行检查。 如果应用安装不成功,用户将收到一条消息以与管理员联系。
示例
下面的代码部分是响应的示例:
{
"type": "AdaptiveCard",
"body": [
{
"type": "TextBlock",
"text": "Looks like you haven't used Disco in this team/chat"
}
],
"actions": [
{
"type": "Action.Submit",
"title": "Continue",
"data": {
"msteams": {
"justInTimeInstall": true
}
}
}
],
"version": "1.0"
}
安装会话机器人后,它会收到另一条包含 name = composeExtensions/submitAction
的调用消息及 value.data.msteams.justInTimeInstall = true
。
示例
下面的代码部分是任务对调用的响应示例:
{
"value": {
"commandId": "giveKudos",
"commandContext": "compose",
"context": {
"theme": "default"
},
"data": {
"msteams": {
"justInTimeInstall": true
}
}
},
"conversation": {
"id": "19:7705841b240044b297123ad7f9c99217@thread.skype"
},
"name": "composeExtension/submitAction",
"imdisplayname": "Bob Smith"
}
对调用的任务响应必须类似于已安装机器人的任务响应。
示例
以下代码部分是使用自适应卡实时安装应用的示例:
private static Attachment GetAdaptiveCardAttachmentFromFile(string fileName)
{
//Read the card json and create attachment.
string[] paths = { ".", "Resources", fileName };
var adaptiveCardJson = File.ReadAllText(Path.Combine(paths));
var adaptiveCardAttachment = new Attachment()
{
ContentType = "application/vnd.microsoft.card.adaptive",
Content = JsonConvert.DeserializeObject(adaptiveCardJson),
};
return adaptiveCardAttachment;
}
代码示例
示例名称 | Description | .NET | Node.js | Python | 清单 |
---|---|---|---|---|---|
Teams 消息扩展操作 | 此示例演示如何定义操作命令、创建对话和响应对话提交操作。 | View | View | View | View |
消息扩展操作预览 | 此示例演示如何使用 Bot Framework v4 在消息传递扩展中使用操作预览。 | View | View | 不适用 | View |
Teams 消息扩展搜索 | 此示例演示如何生成基于搜索的消息扩展。 它会搜索 nudget 包,并在基于搜索的消息扩展中显示结果。 | View | View | View | View |