メッセージ拡張機能を使用した検索

重要

このセクションの記事は、v3 Bot Framework SDK に基づいています。 現在のドキュメント (バージョン 4.6 以降のバージョンの SDK) をお探しの場合は、「 メッセージ拡張機能とのタスク指向の対話 」セクションを参照してください。

検索ベースのメッセージ拡張機能を使用すると、サービスに対してクエリを実行し、その情報をカードの形式でメッセージに直接投稿できます。

メッセージ拡張カードの例を示すスクリーンショット。

次のセクションでは、これを行う方法について説明します。

アプリにメッセージ拡張機能を追加する

メッセージ拡張機能は、ユーザーの要求をリッスンし、 カードなどの構造化データで応答するクラウドホスト型サービスです。 Bot Framework Activity オブジェクトを使用して、サービスをMicrosoft Teamsと統合します。 Bot Builder SDK の .NET および Node.js 拡張機能は、アプリにメッセージ拡張機能機能を追加するのに役立ちます。

Teams のアクション ベースのメッセージ拡張機能を示すスクリーンショット。

Bot Framework に登録する

まず、Microsoft Bot Framework にボットを登録する必要があります。 ボットの Microsoft アプリ ID とコールバック エンドポイントは、そこで定義されているように、メッセージ拡張機能でユーザーの要求を受信して応答するために使用されます。 ボットのMicrosoft Teams チャネルを有効にすることを忘れないでください。

ボット アプリ ID とアプリ パスワードを書き留めます。アプリ マニフェストでアプリ ID を指定する必要があります。

アプリ マニフェストを更新する

ボットとタブと同様に、アプリの マニフェスト を更新してメッセージ拡張機能のプロパティを含めます。 これらのプロパティは、Microsoft Teams クライアントでのメッセージ拡張機能の表示方法と動作を制御します。 メッセージ拡張機能は、マニフェスト v1.0 以降でサポートされています。

メッセージ拡張機能を宣言する

メッセージ拡張機能を追加するには、 composeExtensions プロパティを使用して、マニフェストに新しい最上位の JSON 構造体を含めます。 アプリの 1 つのメッセージ拡張機能を作成することに制限されています。

注:

マニフェストは、メッセージ拡張機能を composeExtensionsとして参照します。 これは、下位互換性を維持するためです。

拡張定義は、次の構造を持つオブジェクトです。

プロパティ名 用途 必須
botId Bot Framework に登録された、ボット用の一意の Microsoft アプリ ID。 これは通常、Teams アプリ全体の ID と同じである必要があります。 必要
scopes この拡張機能を personal スコープまたは team スコープ (またはその両方) に追加できるかどうかを宣言する配列。 必要
canUpdateConfiguration [設定] メニュー項目を有効にします。 いいえ
commands このメッセージ拡張機能がサポートするコマンドの配列。 コマンドは 10 個に制限されています。 必要

注:

canUpdateConfiguration プロパティをアプリ マニフェストでtrueに設定した場合は、メッセージ拡張機能の [設定] メニュー項目を表示できます。 設定を有効にするには、onQuerySettingsUrlonSettingsUpdateも処理する必要があります。

コマンドを定義する

メッセージ拡張機能で 1 つのコマンドを宣言する必要があります。このコマンドは、ユーザーが作成ボックスの [ その他のオプション ()] ボタンからアプリを選択したときに表示されます。

スクリーンショットは、Teams のメッセージ拡張機能の一覧を示す例です。

アプリ マニフェストでは、コマンド項目は次の構造を持つオブジェクトです。

プロパティ名 用途 必須 マニフェストの最小バージョン
id このコマンドに割り当てる一意の ID。 ユーザー要求には、この ID が含まれています。 はい 1.0
title コマンド名。 この値は UI に表示されます。 はい 1.0
description このコマンドの動作を示すヘルプ テキスト。 この値は UI に表示されます。 はい 1.0
type コマンドの種類を設定します。 使用可能な値は、queryaction です。 存在しない場合、既定値は query に設定されます。 いいえ 1.4
initialRun 省略可能なパラメーター。 query コマンドで使用されます。 true に設定されている場合は、ユーザーが UI でこのコマンドを選択するとすぐに、このコマンドを実行する必要があることを示します。 いいえ 1.0
fetchTask 省略可能なパラメーター。 action コマンドで使用されます。 タスク モジュール内に表示するアダプティブ カードまたは Web URL をフェッチするには、true に設定します。 これは、パラメーターの静的セットではなく、 action コマンドへの入力が動的な場合に使用されます。 true に設定すると、コマンドの静的パラメーター リストは無視されることに注意してください。 いいえ 1.4
parameters コマンドのパラメーターの静的リスト。 はい 1.0
parameter.name パラメーターの名前です。 これは、ユーザー要求でサービスに送信されます。 はい 1.0
parameter.description このパラメーターの目的と、指定する必要がある値の例について説明します。 この値は UI に表示されます。 はい 1.0
parameter.title 短い使いやすいパラメーター のタイトルまたはラベル。 はい 1.0
parameter.inputType 必要な入力の種類に設定します。 使用できる値には、 texttextareanumberdatetimetoggleなどがあります。 既定値は text に設定されます。 いいえ 1.4
context メッセージ アクションが使用できるコンテキストを定義する値の省略可能な配列。 使用可能な値は、 messagecompose、または commandBoxです。 既定値は ["compose", "commandBox"] です。 いいえ 1.5

検索の種類のメッセージ拡張機能

検索ベースのメッセージ拡張機能の場合、 type パラメーターを query に設定します。 次に、1 つの検索コマンドを持つマニフェストの例を示します。 1 つのメッセージ拡張機能には、最大 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 に設定した場合は、メッセージ拡張機能の [設定] メニュー項目を有効にし、 onQuerySettingsUrlonSettingsUpdateも処理する必要があります。

onQuery イベントを処理する

メッセージ拡張機能は、メッセージ拡張機能ウィンドウで何らかの処理が行われたり、ウィンドウに送信されたりすると、 onQuery イベントを受け取ります。

メッセージ拡張機能で構成ページを使用する場合、 onQuery のハンドラーは、まず、格納されている構成情報を確認する必要があります。メッセージ拡張機能が構成されていない場合は、構成ページへのリンクを含む config 応答を返します。 構成ページからの応答は、 onQueryによっても処理されます。 唯一の例外は、 onQuerySettingsUrlのハンドラーによって構成ページが呼び出されたときです。次のセクションを参照してください。

メッセージ拡張機能で認証が必要な場合は、ユーザーの状態情報を確認します。 ユーザーがサインインしていない場合は、この記事の後半の 「認証 」セクションの手順に従ってください。

次に、 initialRun が設定されているかどうかを確認します。設定されている場合は、指示の提供や応答の一覧などの適切なアクションを実行します。

onQueryのハンドラーの残りの部分は、ユーザーに情報の入力を求め、プレビュー カードの一覧を表示し、ユーザーが選択したカードを返します。

onQuerySettingsUrl イベントと onSettingsUpdate イベントを処理する

onQuerySettingsUrlイベントとonSettingsUpdateイベントは連携して、[設定] メニュー項目を有効にします。

[設定] メニュー項目の場所を示すスクリーンショット。

onQuerySettingsUrlのハンドラーは、構成ページの URL を返します。構成ページが閉じると、onSettingsUpdateのハンドラーは返された状態を受け入れて保存します。 これは、 onQuerydoesn が構成ページから応答を受け取らない 1 つのケースです。

クエリの受信と応答

メッセージ拡張機能に対するすべての要求は、コールバック URL に投稿される Activity オブジェクトを介して行われます。 要求には、ID やパラメーター値など、ユーザー コマンドに関する情報が含まれています。 要求では、ユーザーとテナント ID など、拡張機能が呼び出されたコンテキストに関するメタデータと、チャット ID またはチャネルとチーム ID も提供されます。

ユーザー要求を受信する

ユーザーがクエリを実行すると、Microsoft Teamsは標準の Bot Framework Activity オブジェクトをサービスに送信します。 サービスは、次の表に示すように、typeinvoke に設定され、nameサポートされているcomposeExtensions型に設定されているActivityのロジックを実行する必要があります。

標準のボット アクティビティプロパティに加えて、ペイロードには次の要求メタデータが含まれています。

プロパティ名 用途
type 要求の種類。を invokeする必要があります。
name サービスに対して発行されるコマンドの種類。 次の種類がサポートされています。
composeExtension/query
composeExtension/querySettingUrl
composeExtension/setting
composeExtension/selectItem
composeExtension/queryLink
from.id 要求を送信したユーザーの ID。
from.name 要求を送信したユーザーの名前。
from.aadObjectId 要求を送信したユーザーの Microsoft Entra オブジェクト ID。
channelData.tenant.id Microsoft Entra テナント ID。
channelData.channel.id チャネル ID (要求がチャネルで行われた場合)。
channelData.team.id チーム ID (要求がチャネルで行われた場合)。
clientInfo ユーザーのメッセージの送信に使用されるクライアント ソフトウェアに関する省略可能なメタデータ。 エンティティには、次の 2 つのプロパティを含めることができます。
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 を使用してサービスにクエリを実行し、カードを返すこともできます。 次のスクリーンショットでは、ユーザーが Azure DevOps の作業項目の URL を貼り付け、メッセージ拡張機能がカードに解決しました。

リンクの展開の例を示すスクリーンショット。

メッセージ拡張機能がこのようにリンクを操作できるようにするには、最初に、例のように 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 要求を発行します。 この間、コードは要求に対する HTTP 応答を提供するために 5 秒です。 この間、サービスは、別の参照、または要求を処理するために必要なその他のビジネス ロジックを実行できます。

サービスは、ユーザー クエリに一致する結果で応答する必要があります。 応答は、 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 UI に表示されます。 プレビューは、次の 2 つの方法のいずれかで生成されます。

  • attachment オブジェクト内で preview プロパティを使用する。 previewの添付ファイルには、ヒーローカードまたはサムネイル カードのみを使用できます。
  • 添付ファイルの基本的な titletextimage プロパティから抽出されます。 これらは、 preview プロパティが設定されておらず、これらのプロパティが使用可能な場合にのみ使用されます。

プレビュー プロパティを設定するだけで、結果リストに Microsoft 365 グループのアダプティブ カードまたはコネクタ カードのプレビューを表示できます。 これは、結果が既にヒーロー カードまたはサムネイル カードである場合は必要ありません。 プレビュー添付ファイルを使用する場合は、ヒーローまたはサムネイル カードである必要があります。 preview プロパティが指定されていない場合、カードのプレビューは失敗し、何も表示されません。

応答の例

この例では、Microsoft 365 グループ用コネクタとアダプティブ カード形式の異なる 2 つの結果を含む応答を示します。 応答で 1 つのカード形式を使用する必要がある場合は、attachments コレクション内の各要素の preview プロパティが、前述のようにヒーローまたはサムネイル形式でプレビューを明示的に定義する必要がある方法を示しています。

{
  "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%)"
          }
        }
      }
    ]
  }
}

既定のクエリ

マニフェストで initialRuntrue に設定Microsoft Teams、ユーザーが最初にメッセージ拡張機能を開いたときに "既定" クエリを発行します。 サービスは、事前設定された結果のセットを使用して、このクエリに応答できます。 これは、最近表示されたアイテム、お気に入り、またはユーザー入力に依存しないその他の情報を表示する場合に役立ちます。

既定のクエリは、文字列値がtrueされるパラメーター initialRunを使用する場合を除き、通常のユーザー クエリと同じ構造です。

既定のクエリの要求の例

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

ユーザーを識別する

サービスに対するすべての要求には、要求を実行したユーザーの難読化された ID と、ユーザーの表示名と Microsoft Entra オブジェクト ID が含まれます。

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

idaadObjectIdの値は、認証された Teams ユーザーの値であることが保証されます。 これらは、資格情報またはサービス内のキャッシュされた状態を検索するためのキーとして使用できます。 さらに、各要求には、ユーザーの Microsoft Entra テナント ID が含まれています。これは、ユーザーの組織を識別するために使用できます。 該当する場合、要求には、要求の送信元のチーム ID とチャネル ID も含まれます。

認証

サービスでユーザー認証が必要な場合は、ユーザーがメッセージ拡張機能を使用する前にユーザーにサインインする必要があります。 ユーザーにサインインするボットまたはタブを作成した場合は、このセクションをよく理解している必要があります。

シーケンスは次のとおりです。

  1. ユーザーがクエリを発行するか、既定のクエリがサービスに自動的に送信されます。
  2. サービスは、Teams ユーザー ID を検査して、ユーザーが最初に認証されたかどうかを確認します。
  3. ユーザーが認証されていない場合は、認証 URL を含むopenUrl推奨されるアクションを使用して、auth応答を送信します。
  4. Microsoft Teams クライアントは、指定された認証 URL を使用して Web ページをホストするポップアップ ウィンドウを起動します。
  5. ユーザーがサインインしたら、ウィンドウを閉じ、Teams クライアントに "認証コード" を送信する必要があります。
  6. その後、Teams クライアントは、手順 5 で渡された認証コードを含むクエリをサービスに再発行します。 サービスは、手順 6 で受け取った認証コードが手順 5 の認証コードと一致することを確認する必要があります。これにより、悪意のあるユーザーがサインイン フローのなりすましや侵害を試みないようにします。 これにより、安全な認証シーケンスを終了させるための 「ループを閉じる」 効果があります。

サインイン アクションで応答する

認証されていないユーザーにサインインを求めるには、認証 URL を含む openUrl 型の推奨アクションで応答します。

サインイン アクションの応答の例

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

注:

サインイン エクスペリエンスを Teams ポップアップでホストするには、URL のドメイン部分がアプリの有効なドメインの一覧に含まれている必要があります。 詳細については、「マニフェスト スキーマのvalidDomains」 を参照してください。

サインイン フローを開始する

サインインは応答性が高く、ポップアップ ウィンドウ内に収まる必要があります。 メッセージ パッシングを使用する Microsoft Teams JavaScript クライアント SDK と統合する必要があります。

Teams 内で実行されている他の埋め込みエクスペリエンスと同様に、ウィンドウ内のコードは最初に microsoftTeams.initialize()を呼び出す必要があります。 コードが OAuth フローを実行する場合は、Teams ユーザー ID をウィンドウに渡し、OAuth サインイン URL の URL に渡すことができます。

サインイン フローを完了する

サインイン要求が完了し、ページにリダイレクトされたら、次の手順を実行する必要があります。

  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

Bot Builder SDK for .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 Samples (Bot Framework のサンプル)