Поделиться через


Поиск с помощью расширений сообщений

Важно!

Статьи в этом разделе основаны на пакете SDK Bot Framework версии 3. Если вы ищете текущую документацию (версии 4.6 или более поздней версии пакета SDK), см. раздел Взаимодействие с расширениями сообщений, ориентированное на задачи .

Расширения сообщений на основе поиска позволяют запрашивать службу и публиковать эту информацию в виде карточки прямо в сообщении.

Снимок экрана: пример карточки расширения сообщения.

В следующих разделах описано, как это сделать.

Добавление расширения сообщений в приложение

Расширение сообщений — это облачная служба, которая прослушивает запросы пользователей и отвечает структурированными данными, такими как карточка. Вы интегрируете службу с Microsoft Teams с помощью объектов Bot Framework Activity . Расширения .NET и Node.js для пакета SDK Bot Builder помогут вам добавить в приложение функциональные возможности расширения сообщений.

Снимок экрана: расширение сообщений на основе действий в Teams.

Регистрация в Bot Framework

Сначала необходимо зарегистрировать бота в Microsoft Bot Framework. Идентификатор приложения Майкрософт и конечные точки обратного вызова для бота, как определено там, используются в расширении сообщений для получения запросов пользователей и ответа на них. Не забудьте включить канал Microsoft Teams для бота.

Запишите идентификатор приложения бота и пароль приложения. Необходимо указать идентификатор приложения в манифесте приложения.

Обновление манифеста приложения

Как и в случае с ботами и вкладками, вы обновляете манифест приложения, включив в него свойства расширения сообщений. Эти свойства определяют, как расширение сообщений отображается и ведет себя в клиенте Microsoft Teams. Расширения сообщений поддерживаются начиная с манифеста версии 1.0.

Объявление расширения сообщений

Чтобы добавить расширение сообщения, добавьте в манифест новую структуру JSON верхнего уровня со свойством composeExtensions . Вы можете создать одно расширение для сообщений для приложения.

Примечание.

Манифест ссылается на расширения сообщений как composeExtensions. Это необходимо для обеспечения обратной совместимости.

Определение расширения — это объект, имеющий следующую структуру:

Имя свойства Назначение Обязательный?
botId Уникальный идентификатор приложения Майкрософт для бота, зарегистрированный в Bot Framework. Обычно он должен совпадать с идентификатором общего приложения Teams. Да
scopes Массив, объявляющий, может ли это расширение быть добавлено в personal области или team (или и то, и другое). Да
canUpdateConfiguration Включает пункт меню "Параметры ". Нет
commands Массив команд, поддерживаемых этим расширением сообщений. Вы можете использовать только 10 команд. Да

Примечание.

Если для свойства задано canUpdateConfiguration значение true в манифесте приложения, можно отобразить пункт меню Параметры для расширения сообщения. Чтобы включить параметры, необходимо также обработать onQuerySettingsUrl и onSettingsUpdate.

Определение команд

Расширение сообщений должно объявить одну команду, которая появляется, когда пользователь выбирает приложение с помощью кнопки Дополнительные параметры () в поле создания.

Снимок экрана: пример, на котором показан список расширений сообщений в Teams.

В манифесте приложения элемент команды представляет собой объект со следующей структурой:

Имя свойства Назначение Обязательный? Минимальная версия манифеста
id Уникальный идентификатор, назначенный этой команде. Запрос пользователя включает этот идентификатор. Да 1.0
title Имя команды. Это значение выводится в пользовательском интерфейсе. Да 1.0
description Текст справки, указывающий, что делает эта команда. Это значение выводится в пользовательском интерфейсе. Да 1.0
type Задайте тип команды. Возможные значения: query и action. Если этот параметр отсутствует, по умолчанию задается queryзначение . Нет 1.4
initialRun Необязательный параметр, используемый с query командами. Если задано значение true, указывает, что эта команда должна быть выполнена, как только пользователь выберет эту команду в пользовательском интерфейсе. Нет 1.0
fetchTask Необязательный параметр, используемый с action командами. Задайте значение true , чтобы получить адаптивную карточку или URL-адрес веб-сайта для отображения в модуле задачи. Используется, если входные данные action команды являются динамическими, а не статическими наборами параметров. Обратите внимание, что если задано значение true, статический список параметров для команды игнорируется. Нет 1.4
parameters Статический список параметров для команды. Да 1.0
parameter.name Имя параметра. Оно отправляется в службу в составе запроса пользователя. Да 1.0
parameter.description Описывает цели этого параметра и пример значения, которое должно быть предоставлено. Это значение выводится в пользовательском интерфейсе. Да 1.0
parameter.title Короткое понятное название параметра или метка. Да 1.0
parameter.inputType Задайте необходимый тип входных данных. Возможные значения: text, textarea, number, date, time, . toggle По умолчанию задано значение text. Нет 1.4
context Необязательный массив значений, определяющий контекст, в который доступно действие сообщения. Возможные значения: message, composeили commandBox. Значение по умолчанию: ["compose", "commandBox"]. Нет 1.5

Расширения сообщений типа поиска

Для расширения сообщений на основе поиска задайте type параметру значение query. Ниже приведен пример манифеста с одной командой поиска. С одним расширением сообщений может быть связано до 10 различных команд. Это может включать в себя как несколько поисковых, так и команд на основе действий.

Пример полного манифеста приложения

{
  "$schema": "https://developer.microsoft.com/json-schemas/teams/v1.8/MicrosoftTeams.schema.json",
  "manifestVersion": "1.5",
  "version": "1.0",
  "id": "57a3c29f-1fc5-4d97-a142-35bb662b7b23",
  "developer": {
    "name": "John Developer",
    "websiteUrl": "http://bingbotservice.azurewebsites.net/",
    "privacyUrl": "http://bingbotservice.azurewebsites.net/privacy",
    "termsOfUseUrl": "http://bingbotservice.azurewebsites.net/termsofuse"
  },
  "name": {
    "short": "Bing",
    "full": "Bing"
  },
  "description": {
    "short": "Find Bing search results",
    "full": "Find Bing search results and share them with your team members."
  },
  "icons": {
    "outline": "bing-outline.jpg",
    "color": "bing-color.jpg"
  },
  "accentColor": "#ff6a00",
  "composeExtensions": [
    {
      "botId": "57a3c29f-1fc5-4d97-a142-35bb662b7b23",
      "canUpdateConfiguration": true,
      "commands": [{
          "id": "searchCmd",
          "description": "Search Bing for information on the web",
          "title": "Search",
          "initialRun": true,
          "parameters": [{
            "name": "searchKeyword",
            "description": "Enter your search keywords",
            "title": "Keywords"
          }]
        }
      ]
    }
  ],
  "permissions": [
    "identity",
    "messageTeamMembers"
  ],
  "validDomains": [
    "bingbotservice.azurewebsites.net",
    "*.bingbotservice.azurewebsites.net"
  ]
}

Тестирование с помощью отправки

Вы можете протестировать расширение для сообщений, отправив приложение.

Чтобы открыть расширение для сообщений, перейдите в любой из чатов или каналов. Нажмите кнопку Дополнительные параметры () в поле создания и выберите расширение сообщения.

Добавление обработчиков событий

Большая часть вашей работы связана с событием onQuery , которое обрабатывает все взаимодействия в окне расширения сообщения.

Если в манифесте задано значение canUpdateConfigurationtrue , вы включите пункт меню Параметры для расширения сообщений, а также должны обрабатывать onQuerySettingsUrl и onSettingsUpdate.

Обработка событий onQuery

Расширение сообщений получает событие, onQuery когда что-либо происходит в окне расширения сообщения или отправляется в окно.

Если расширение сообщений использует страницу конфигурации, обработчик для onQuery должен сначала проверить наличие хранимых сведений config о конфигурации. Если расширение сообщения не настроено, верните ответ со ссылкой на страницу конфигурации. Ответ со страницы конфигурации также обрабатывается .onQuery Единственным исключением является то, что страница конфигурации вызывается обработчиком для onQuerySettingsUrl; см. следующий раздел:

Если для расширения сообщений требуется проверка подлинности, проверьте сведения о состоянии пользователя. Если пользователь не вошел в систему, следуйте инструкциям в разделе Проверка подлинности далее в этой статье.

Затем проверьте, задано ли initialRun значение. Если да, выполните соответствующие действия, например предоставить инструкции или список ответов.

Оставшаяся часть обработчика onQuery запрашивает у пользователя сведения, отображает список карточек предварительного просмотра и возвращает карточку, выбранную пользователем.

Обработка событий onQuerySettingsUrl и onSettingsUpdate

События onQuerySettingsUrl и onSettingsUpdate работают вместе, чтобы включить пункт меню Параметры .

Снимок экрана: расположение пункта меню

Обработчик для onQuerySettingsUrl возвращает URL-адрес страницы конфигурации. После закрытия страницы конфигурации обработчик для onSettingsUpdate принимает и сохраняет возвращенное состояние. Это тот случай, в котором onQueryне получает ответ со страницы конфигурации.

Получение запросов и реагирование на них

Каждый запрос к расширению сообщений выполняется через Activity объект, который отправляется в URL-адрес обратного вызова. Запрос содержит сведения о команде пользователя, например идентификатор и значения параметров. Запрос также предоставляет метаданные о контексте, в котором было вызвано расширение, включая идентификатор пользователя и клиента, а также идентификаторы чата или канала и команды.

Получение запросов пользователей

Когда пользователь выполняет запрос, Microsoft Teams отправляет службе стандартный объект Bot Framework Activity . Ваша служба должна выполнять свою логику для объекта Activity , для type которого задано invoke значение и name задано значение поддерживаемого composeExtensions типа, как показано в следующей таблице.

Помимо стандартных свойств действий бота полезные данные содержат следующие метаданные запроса:

Имя свойства Назначение
type Тип запроса; должен иметь значение invoke.
name Тип команды, выпущенной для вашей службы. Поддерживаются следующие типы:
composeExtension/query
composeExtension/querySettingUrl
composeExtension/setting
composeExtension/selectItem
composeExtension/queryLink
from.id Идентификатор пользователя, отправившего запрос.
from.name Имя пользователя, отправившего запрос.
from.aadObjectId Идентификатор объекта Microsoft Entra пользователя, отправляющего запрос.
channelData.tenant.id Идентификатор клиента Microsoft Entra.
channelData.channel.id Идентификатор канала (если запрос был выполнен в канале).
channelData.team.id Идентификатор команды (если запрос был выполнен в канале).
clientInfo Необязательные метаданные о клиентском программном обеспечении, используемом для отправки сообщения пользователя. Сущность может содержать два свойства:
Поле country содержит обнаруженное расположение пользователя.
В platform поле описывается клиентская платформа обмена сообщениями.
Дополнительные сведения см. в разделеТипы сущностей, отличные от IRI, — clientInfo.

Параметры запроса находятся в объекте value, который включает следующие свойства:

Имя свойства Назначение
commandId Имя команды, вызываемой пользователем, соответствующее одной из команд, объявленных в манифесте приложения.
parameters Массив параметров. Каждый объект параметра содержит имя параметра, а также значение параметра, предоставленное пользователем.
queryOptions Параметры разбиения на страницы:
skip: количество пропусков для этого запроса
count: количество возвращаемых элементов

Пример запроса

{
  "name": "composeExtension/query",
  "value": {
    "commandId": "searchCmd",
    "parameters": [
      {
        "name": "searchKeywords",
        "value": "Toronto"
      }
    ],
    "queryOptions": {
      "skip": 0,
      "count": 25
    }
  },
  "type": "invoke",
  "timestamp": "2017-05-01T15:45:51.876Z",
  "localTimestamp": "2017-05-01T08:45:51.876-07:00",
  "id": "f:622749630322482883",
  "channelId": "msteams",
  "serviceUrl": "https://smba.trafficmanager.net/amer-client-ss.msg/",
  "from": {
    "id": "29:1C7dbRrC_5yzN1RGtZIrcWT0xz88KPGP9sxdpVpV8sODlgPHeQE9RqQ02hnpuKzy6zZ-AaZx6swUOMj_Dsdse3TQ4sIaeebbFBF-VgjJy_nY",
    "name": "Larry Jin",
    "aadObjectId": "cd723fa0-0591-416a-9290-e93ecf3a9b92"
  },
  "conversation": {
    "id": "19:skypespaces_8198cfe0dd2647ae91930f0974768a40@thread.skype"
  },
  "recipient": {
    "id": "28:b4922ea1-5315-4fd0-9b21-d941ab06e39f",
    "name": "TheComposeExtensionDev"
  },
  "entities": [
    {
    "type": "clientInfo",
      "country": "US",
      "platform": "Windows"
    }
  ]
}

В качестве альтернативы (или в дополнение) к поиску во внешней службе можно использовать URL-адрес, вставленный в окно создания сообщения, чтобы запросить службу и вернуть карточку. На снимке экрана ниже пользователь вставил URL-адрес рабочего элемента в Azure DevOps, который расширение сообщения разрешило в карточку.

Снимок экрана: пример распаковки ссылок.

Чтобы расширение сообщений взаимодействовать со ссылками таким образом, сначала необходимо добавить массив в messageHandlers манифест приложения, как показано в примере:

"composeExtensions": [
  {
    "botId": "abc123456-ab12-ab12-ab12-abcdef123456",
    "messageHandlers": [
      {
        "type": "link",
        "value": {
          "domains": [
            "*.trackeddomain.com"
          ]
        }
      }
    ]
  }
]

После добавления домена для прослушивания манифеста приложения необходимо изменить код бота, чтобы ответить на приведенный ниже запрос на вызов.

{
  "type": "invoke",
  "name": "composeExtension/queryLink",
  "value": {
    "url": "https://theurlsubmittedbyyouruser.trackeddomain.com/id/1234"
  }
}

Если приложение возвращает несколько элементов, используется только первый.

Реагирование на запросы пользователей

Когда пользователь выполняет запрос, Teams отправляет синхронный HTTP-запрос к вашей службе. В течение этого времени у кода есть 5 секунд, чтобы предоставить HTTP-ответ на запрос. В течение этого времени служба может выполнить другой поиск или любую другую бизнес-логику, необходимую для обслуживания запроса.

Ваша служба должна ответить результатами, соответствующими запросу пользователя. В ответе должен быть указан код 200 OK состояния HTTP и допустимый объект application/json со следующим текстом:

Имя свойства Назначение
composeExtension Конверт ответа верхнего уровня.
composeExtension.type Тип ответа. Поддерживаются следующие типы:
result: отображает список результатов поиска.
auth: запрашивает проверку подлинности пользователя.
config: предлагает пользователю настроить расширение сообщений.
message: показывает обычное текстовое сообщение
composeExtension.attachmentLayout Задает макет вложений. Используется для ответов типа result.
Поддерживаются следующие типы:
list: список объектов карточек, содержащих поля эскизов, заголовков и текстовых полей.
grid: сетка эскизов изображений
composeExtension.attachments Массив допустимых объектов вложений. Используется для ответов типа result.
Поддерживаются следующие типы:
application/vnd.microsoft.card.thumbnail
application/vnd.microsoft.card.hero
application/vnd.microsoft.teams.card.o365connector
application/vnd.microsoft.card.adaptive
composeExtension.suggestedActions Предлагаемые действия. Используется для ответов типа auth или config.
composeExtension.text Отображаемое сообщение. Используется для ответов типа message.

Типы и предварительные версии карточек ответа

Поддерживаются следующие типы вложений:

Дополнительные сведения см. в разделе Общие сведения о карточках .

Сведения об использовании типов эскизов и карточек-героев см. в статье Добавление карточек и действий с карточками.

Дополнительные сведения о карточке соединителя для групп Microsoft 365 см. в статье Использование карточки соединителя для групп Microsoft 365.

Список результатов отображается в пользовательском интерфейсе Microsoft Teams с предварительным просмотром каждого элемента. Предварительная версия создается одним из двух способов:

  • preview Использование свойства в объекте attachment . Вложение preview может быть только карточкой "Герой" или "Эскиз".
  • Извлекается из основных titleсвойств , textи image вложения. Они используются только в том случае, preview если свойство не задано и эти свойства доступны.

Вы можете отобразить предварительную версию адаптивной карточки или карточки соединителя для групп Microsoft 365 в списке результатов, просто задав его свойство предварительного просмотра. Это не обязательно, если результаты уже являются карточками-героями или эскизами. Если вы используете вложение предварительного просмотра, оно должно быть карточкой "Герой" или "Эскиз". Если свойство предварительного просмотра не указано, предварительный просмотр карточки завершается ошибкой и ничего не отображается.

Пример ответа

В этом примере показан ответ с двумя результатами, сочетающими различные форматы карточек: Соединитель для групп Microsoft 365 и Адаптивный. Хотя вы, скорее всего, захотите придерживаться одного формата карточки в ответе, в нем показано, как preview свойство каждого элемента в attachments коллекции должно явно определять предварительный просмотр в формате главного элемента или эскиза, как описано выше.

{
  "composeExtension": {
    "type": "result",
    "attachmentLayout": "list",
    "attachments": [
      {
        "contentType": "application/vnd.microsoft.teams.card.o365connector",
        "content": {
          "sections": [
            {
              "activityTitle": "[85069]: Create a cool app",
              "activityImage": "https://placekitten.com/200/200"
            },
            {
              "title": "Details",
              "facts": [
                {
                  "name": "Assigned to:",
                  "value": "[Larry Brown](mailto:larryb@example.com)"
                },
                {
                  "name": "State:",
                  "value": "Active"
                }
              ]
            }
          ]
        },
        "preview": {
          "contentType": "application/vnd.microsoft.card.thumbnail",
          "content": {
            "title": "85069: Create a cool app",
            "images": [
              {
                "url": "https://placekitten.com/200/200"
              }
            ]
          }
        }
      },
      {
        "contentType": "application/vnd.microsoft.card.adaptive",
        "content": {
          "type": "AdaptiveCard",
          "body": [
            {
              "type": "Container",
              "items": [
                {
                  "type": "TextBlock",
                  "text": "Microsoft Corp (NASDAQ: MSFT)",
                  "size": "medium",
                  "isSubtle": true
                },
                {
                  "type": "TextBlock",
                  "text": "September 19, 4:00 PM EST",
                  "isSubtle": true
                }
              ]
            },
            {
              "type": "Container",
              "spacing": "none",
              "items": [
                {
                  "type": "ColumnSet",
                  "columns": [
                    {
                      "type": "Column",
                      "width": "stretch",
                      "items": [
                        {
                          "type": "TextBlock",
                          "text": "75.30",
                          "size": "extraLarge"
                        },
                        {
                          "type": "TextBlock",
                          "text": "▼ 0.20 (0.32%)",
                          "size": "small",
                          "color": "attention",
                          "spacing": "none"
                        }
                      ]
                    },
                    {
                      "type": "Column",
                      "width": "auto",
                      "items": [
                        {
                          "type": "FactSet",
                          "facts": [
                            {
                              "title": "Open",
                              "value": "62.24"
                            },
                            {
                              "title": "High",
                              "value": "62.98"
                            },
                            {
                              "title": "Low",
                              "value": "62.20"
                            }
                          ]
                        }
                      ]
                    }
                  ]
                }
              ]
            }
          ],
          "version": "1.0"
        },
        "preview": {
          "contentType": "application/vnd.microsoft.card.thumbnail",
          "content": {
            "title": "Microsoft Corp (NASDAQ: MSFT)",
            "text": "75.30 ▼ 0.20 (0.32%)"
          }
        }
      }
    ]
  }
}

Запрос по умолчанию

Если в манифесте задано значение initialRun , true Microsoft Teams выдает запрос по умолчанию, когда пользователь впервые открывает расширение сообщения. Ваша служба может ответить на этот запрос набором предварительно заполненных результатов. Это может быть полезно для отображения, например, недавно просмотрированных элементов, избранного или любой другой информации, которая не зависит от введенных пользователем данных.

Запрос по умолчанию имеет ту же структуру, что и любой обычный запрос пользователя, за исключением параметра initialRun , строковое значение которого равно true.

Пример запроса для запроса по умолчанию

{
  "type": "invoke",
  "name": "composeExtension/query",
  "value": {
    "commandId": "searchCmd",
    "parameters": [
      {
        "name": "initialRun",
        "value": "true"
      }
    ],
    "queryOptions": {
      "skip": 0,
      "count": 25
    }
  },
  ⋮
}

Идентификация пользователя

Каждый запрос к службам включает скрытый идентификатор пользователя, который выполнил запрос, а также отображаемое имя пользователя и идентификатор объекта Microsoft Entra.

"from": {
  "id": "29:1C7dbRrC_5yzN1RGtZIrcWT0xz88KPGP9sxdpVpV8sODlgPHeQE9RqQ02hnpuKzy6zZ-AaZx6swUOMj_Dsdse3TQ4sIaeebbFBF-VgjJy_nY",
  "name": "Larry Jin",
  "aadObjectId": "cd723fa0-0591-416a-9290-e93ecf3a9b92"
},

Значения id и aadObjectId гарантированно будут значениями пользователя Teams, прошедшего проверку подлинности. Их можно использовать в качестве ключей для поиска учетных данных или любого кэшированного состояния в службе. Кроме того, каждый запрос содержит идентификатор клиента Microsoft Entra пользователя, который можно использовать для идентификации организации пользователя. Если применимо, запрос также содержит идентификаторы команды и каналов, из которых был получен запрос.

Проверка подлинности

Если вашей службе требуется проверка подлинности пользователя, необходимо войти в систему, прежде чем пользователь сможет использовать расширение сообщений. Если вы написали бот или вкладку, которая выполняет вход пользователя, этот раздел должен быть знаком.

Последовательность выглядит следующим образом:

  1. Пользователь отправляет запрос, или запрос по умолчанию автоматически отправляется в службу.
  2. Служба проверяет, прошел ли пользователь проверку подлинности, проверив идентификатор пользователя Teams.
  3. Если пользователь не прошел проверку подлинности, отправьте ответ auth с предложенным действием openUrl , включая URL-адрес проверки подлинности.
  4. Клиент Microsoft Teams запускает всплывающее окно, на котором размещена веб-страница, используя указанный URL-адрес проверки подлинности.
  5. После входа пользователя следует закрыть окно и отправить "код проверки подлинности" в клиент Teams.
  6. Затем клиент Teams перезапустит запрос к вашей службе, который включает код проверки подлинности, переданный на шаге 5. Ваша служба должна убедиться, что код проверки подлинности, полученный на шаге 6, соответствует коду из шага 5, что гарантирует, что злоумышленник не пытается подделать или скомпрометировать поток входа. Это фактически "закрывает цикл" для завершения последовательности надежной проверки подлинности.

Ответ с помощью действия входа

Чтобы предложить пользователю, не прошедшему проверку подлинности, выполнить вход, в ответном сообщении предложите ему выполнить действие типа openUrl и укажите URL-адрес проверки подлинности.

Пример ответа для действия входа

{
  "composeExtension":{
    "type":"auth",
    "suggestedActions":{
      "actions":[
        {
          "type": "openUrl",
          "value": "https://example.com/auth",
          "title": "Sign in to this app"
        }
      ]
    }
  }
}

Примечание.

Чтобы интерфейс входа размещался во всплывающем окне Teams, доменная часть URL-адреса должна находиться в списке допустимых доменов приложения. Дополнительные сведения см. в разделе validDomains в схеме манифеста.

Запуск потока входа

Ваш вход должен быть адаптивным и помещаться во всплывающем окне. Он должен интегрироваться с клиентским пакетом SDK Microsoft Teams JavaScript, который использует передачу сообщений.

Как и в случае с другими внедренными интерфейсами, выполняемыми в Teams, код в окне должен сначала вызвать microsoftTeams.initialize(). Если код выполняет поток OAuth, вы можете передать идентификатор пользователя Teams в окно, а затем передать его по URL-адресу для входа в OAuth.

Завершение потока входа

Когда запрос на вход завершится и перенаправляется на страницу, он должен выполнить следующие действия:

  1. Создайте код безопасности. (Это может быть случайное число.) Необходимо кэшировать этот код в службе вместе с учетными данными, полученными при входе, например маркерами OAuth 2.0.
  2. Вызовите microsoftTeams.authentication.notifySuccess и передайте код безопасности.

На этом этапе окно закрывается, а управление передается клиенту Teams. Теперь клиент может повторно выполнить исходный запрос пользователя вместе с кодом безопасности в свойстве state . Ваша программа может использовать код безопасности для поиска учетных данных, сохраненных ранее, для завершения последовательности проверки подлинности, а затем для выполнения запроса пользователя.

Пример повторно отправленного запроса

{
    "name": "composeExtension/query",
    "value": {
        "commandId": "insertWiki",
        "parameters": [{
            "name": "searchKeyword",
            "value": "lakers"
        }],
        "state": "12345",
        "queryOptions": {
            "skip": 0,
            "count": 25
        }
    },
    "type": "invoke",
    "timestamp": "2017-04-26T05:18:25.629Z",
    "localTimestamp": "2017-04-25T22:18:25.629-07:00",
    "entities": [{
        "type": "clientInfo",
        "country": "US",
        "platform": "Web",
        
    }],
    "text": "",
    "attachments": [],
    "address": {
        "id": "f:7638210432489287768",
        "channelId": "msteams",
        "user": {
            "id": "29:1A5TJWHkbOwSyu_L9Ktk9QFI1d_kBOEPeNEeO1INscpKHzHTvWfiau5AX_6y3SuiOby-r73dzHJ17HipUWqGPgw",
            "aadObjectId": "fc8ca1c0-d043-4af6-b09f-141536207403"
        },
        "conversation": {
            "id": "19:7705841b240044b297123ad7f9c99217@thread.skype"
        },
        "bot": {
            "id": "28:c073afa8-7e77-4f92-b3e7-aa589e952a3e",
            "name": "maotestbot2"
        },
        "serviceUrl": "https://smba.trafficmanager.net/amer-client-ss.msg/",
        "useAuth": true
    },
    "source": "msteams"
}

Поддержка пакета SDK

.NET

Чтобы получать и обрабатывать запросы с помощью пакета SDK Bot Builder для .NET, можно проверить invoke тип действия для входящего действия, а затем использовать вспомогательный метод в пакете NuGet Microsoft.Bot.Connector.Teams , чтобы определить, является ли это действие расширением сообщений.

Пример кода в .NET

public async Task<HttpResponseMessage> Post([FromBody]Activity activity)
{
    if (activity.Type == ActivityTypes.Invoke) // Received an invoke
    {
        if (activity.IsComposeExtensionQuery())
        {
            // This is the response object that will get sent back to the messaging extension request.
            ComposeExtensionResponse invokeResponse = null;

            // This helper method gets the query as an object.
            var query = activity.GetComposeExtensionQueryData();

            if (query.CommandId != null && query.Parameters != null && query.Parameters.Count > 0)
            {
                // query.Parameters has the parameters sent by client
                var results = new ComposeExtensionResult()
                {
                    AttachmentLayout = "list",
                    Type = "result",
                    Attachments = new List<ComposeExtensionAttachment>(),
                };
                invokeResponse.ComposeExtension = results;
            }

            // Return the response
            return Request.CreateResponse<ComposeExtensionResponse>(HttpStatusCode.OK, invokeResponse);
        } else
        {
            // Handle other types of Invoke activities here.
        }
    } else {
      // Failure case catch-all.
      var response = Request.CreateResponse(HttpStatusCode.BadRequest);
      response.Content = new StringContent("Invalid request! This API supports only messaging extension requests. Check your query and try again");
      return response;
    }
}

Node.js

Пример кода в Node.js

require('dotenv').config();

import * as restify from 'restify';
import * as builder from 'botbuilder';
import * as teamBuilder from 'botbuilder-teams';

class App {
    run() {
        const server = restify.createServer();
        let teamChatConnector = new teamBuilder.TeamsChatConnector({
            appId: process.env.MICROSOFT_APP_ID,
            appPassword: process.env.MICROSOFT_APP_PASSWORD
        });

        // Command ID must match what's defined in manifest
        teamChatConnector.onQuery('<%= commandId %>',
            (event: builder.IEvent,
            query: teamBuilder.ComposeExtensionQuery,
            callback: (err: Error, result: teamBuilder.IComposeExtensionResponse, statusCode: number) => void) => {
                // Check for initialRun; i.e., when you should return default results
                // if (query.parameters[0].name === 'initialRun') {}

                // Check query.queryOptions.count and query.queryOptions.skip for paging

                // Return auth response
                // let response = teamBuilder.ComposeExtensionResponse.auth().actions([
                //     builder.CardAction.openUrl(null, 'https://authUrl', 'Please sign in')
                // ]).toResponse();

                // Return config response
                // let response = teamBuilder.ComposeExtensionResponse.config().actions([
                //     builder.CardAction.openUrl(null, 'https://configUrl', 'Please sign in')
                // ]).toResponse();

                // Return result response
                let response = teamBuilder.ComposeExtensionResponse.result('list').attachments([
                    new builder.ThumbnailCard()
                        .title('Test thumbnail card')
                        .text('This is a test thumbnail card')
                        .images([new builder.CardImage().url('https://bot-framework.azureedge.net/bot-icons-v1/bot-framework-default-9.png')])
                        .toAttachment()
                ]).toResponse();
                callback(null, response, 200);
            });
        server.post('/api/composeExtension', teamChatConnector.listen());
        server.listen(process.env.PORT, () => console.log(`listening to port:` + process.env.PORT));
    }
}

const app = new App();
app.run();

Дополнительные ресурсы

Примеры Bot Framework