Pesquisar com extensões de mensagem

Importante

Os artigos nesta seção são baseados no SDK do Bot Framework v3. Se você estiver procurando a documentação atual (versão 4.6 ou posterior do SDK), consulte a seção Interações orientadas à tarefa com extensões de mensagem.

As extensões de mensagem baseadas em pesquisa permitem consultar seu serviço e postar essas informações na forma de um cartão, diretamente em sua mensagem.

A captura de tela mostra o exemplo de cartão de extensão de mensagem.

As seções a seguir descrevem como fazer isso:

Adicionar uma extensão de mensagem ao seu aplicativo

Uma extensão de mensagem é um serviço hospedado na nuvem que escuta solicitações do usuário e responde com dados estruturados, como um cartão. Você integra seu serviço ao Microsoft Teams por meio de objetos do Bot Framework Activity . Nossas extensões .NET e Node.js para o SDK do Construtor de Bots podem ajudá-lo a adicionar a funcionalidade de extensão de mensagem ao seu aplicativo.

Captura de tela que mostra a extensão de mensagem baseada em ação no Teams.

Registrar-se no Bot Framework

Se você ainda não tiver feito isso, primeiro deve registrar um bot com o Microsoft Bot Framework. A ID do aplicativo Microsoft e os pontos de extremidade de retorno de chamada para seu bot, conforme definido lá, serão usados na extensão da mensagem para receber e responder às solicitações do usuário. Lembre-se de habilitar o canal do Microsoft Teams para o bot.

Anote a ID do aplicativo bot e a senha do aplicativo, você precisará fornecer a ID do aplicativo no manifesto do aplicativo.

Atualizar seu manifesto do aplicativo

Assim como acontece com bots e guias, você atualiza o manifesto do aplicativo para incluir as propriedades de extensão da mensagem. Essas propriedades regem como sua extensão de mensagem aparece e se comporta no cliente do Microsoft Teams. Há suporte para extensões de mensagem começando com manifesto v1.0.

Declarar sua extensão de mensagem

Para adicionar uma extensão de mensagem, inclua uma nova estrutura JSON de nível superior no manifesto com a composeExtensions propriedade. Atualmente, você está limitado a criar uma única extensão de mensagem para seu aplicativo.

Observação

O manifesto refere-se a extensões de mensagem como composeExtensions. Isso é para manter a compatibilidade com atrasos.

A definição de extensão é um objeto que tem a seguinte estrutura:

Nome da propriedade Objetivo Obrigatório?
botId O ID exclusivo do aplicativo Microsoft para o bot conforme registrado na estrutura do bot. Normalmente, isso deve ser o mesmo que a ID do aplicativo do Teams geral. Sim
scopes Matriz declarando se essa extensão pode ser adicionada a personal ou team escopos (ou ambos). Sim
canUpdateConfiguration Habilita o item de menu Configurações . Não
commands Matriz de comandos que essa extensão de mensagem dá suporte. Você está limitado a 10 comandos. Sim

Definir comandos

Sua extensão de mensagem deve declarar um comando, que aparece quando o usuário seleciona seu aplicativo no botão Mais opções () na caixa de composição.

Captura de tela é um exemplo que mostra uma lista de extensões de mensagens no Teams.

No manifesto do aplicativo, o item de comando é um objeto com a seguinte estrutura:

Nome da propriedade Objetivo Obrigatório? Versão mínima do manifesto
id ID exclusiva que você atribui a este comando. A solicitação do usuário incluirá essa ID. Sim 1.0
title Nome do comando. Esse valor aparece na interface do usuário. Sim 1.0
description Texto de ajuda que indica o que esse comando faz. Esse valor aparece na interface do usuário. Sim 1.0
type Defina o tipo de comando. Os valores possíveis incluem query e action. Se não estiver presente, o valor padrão será definido como query. Não 1.4
initialRun Parâmetro opcional, usado com query comandos. Se definido como true, indica que esse comando deve ser executado assim que o usuário escolher esse comando na interface do usuário. Não 1.0
fetchTask Parâmetro opcional, usado com action comandos. Defina como true para buscar o cartão adaptável ou a url da Web a ser exibido no módulo de tarefa. Isso é usado quando a entrada no action comando é dinâmica em oposição a um conjunto estático de parâmetros. Observe que, se definido como true, a lista de parâmetros estáticos para o comando será ignorada. Não 1.4
parameters Lista estática de parâmetros para o comando. Sim 1.0
parameter.name O nome do parâmetro. Isso é enviado ao seu serviço na solicitação do usuário. Sim 1.0
parameter.description Descreve as finalidades desse parâmetro e o exemplo do valor que deve ser fornecido. Esse valor aparece na interface do usuário. Sim 1.0
parameter.title Título ou rótulo de parâmetro amigável ao usuário curto. Sim 1.0
parameter.inputType Defina como o tipo de entrada necessário. Os valores possíveis incluem , , , , , toggletime. datenumbertextareatext O padrão é definido como text. Não 1.4
context Matriz opcional de valores que define o contexto em que a ação da mensagem está disponível. Os valores possíveis são message, composeou commandBox. O padrão é ["compose", "commandBox"]. Não 1,5

Extensões de mensagem de tipo de pesquisa

Para a extensão de mensagem baseada em pesquisa, defina o type parâmetro como query. Abaixo está um exemplo de um manifesto com um único comando de pesquisa. Uma única extensão de mensagem pode ter até 10 comandos diferentes associados a ela. Isso pode incluir várias pesquisas e vários comandos baseados em ação.

Exemplo de manifesto de aplicativo completo

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

Testar por meio do carregamento

Você pode testar sua extensão de mensagem carregando seu aplicativo.

Para abrir sua extensão de mensagem, acesse qualquer um dos seus chats ou canais. Escolha o botão Mais opções () na caixa de composição e escolha sua extensão de mensagem.

Adicionar manipuladores de eventos

A maior parte do seu trabalho envolve o onQuery evento, que manipula todas as interações na janela de extensão da mensagem.

Se você definir canUpdateConfiguration como true no manifesto, habilitará o item de menu Configurações para sua extensão de mensagem e também deverá manipular onQuerySettingsUrl e onSettingsUpdate.

Manipular eventos onQuery

Uma extensão de mensagem recebe um onQuery evento quando algo acontece na janela de extensão da mensagem ou é enviado para a janela.

Se sua extensão de mensagem usar uma página de configuração, o manipulador onQuery deve primeiro marcar para qualquer informação de configuração armazenada; se a extensão da mensagem não estiver configurada, retorne uma config resposta com um link para sua página de configuração. A resposta da página de configuração também é tratada por onQuery. A única exceção é quando a página de configuração é chamada pelo manipulador para onQuerySettingsUrl; confira a seguinte seção:

Se sua extensão de mensagem exigir autenticação, marcar as informações de estado do usuário. Se o usuário não estiver conectado, siga as instruções na seção Autenticação posteriormente neste artigo.

Em seguida, marcar se initialRun está definido; se for o caso, tome as medidas apropriadas, como fornecer instruções ou uma lista de respostas.

O restante do manipulador para onQuery solicita informações ao usuário, exibe uma lista de cartões de visualização e retorna o cartão selecionado pelo usuário.

Manipular eventos onQuerySettingsUrl e onSettingsUpdate

Os onQuerySettingsUrl eventos e onSettingsUpdate funcionam juntos para habilitar o item de menu Configurações .

A captura de tela mostra os locais do item de menu Configurações.

Seu manipulador para onQuerySettingsUrl retorna a URL da página de configuração; após o fechamento da página de configuração, o manipulador aceita onSettingsUpdate e salva o estado retornado. Esse é o único caso em que onQuerynão recebe a resposta da página de configuração.

Receber e responder a consultas

Cada solicitação para sua extensão de mensagem é feita por meio de um Activity objeto que é postado na URL de retorno de chamada. A solicitação contém informações sobre o comando do usuário, como ID e valores de parâmetro. A solicitação também fornece metadados sobre o contexto em que sua extensão foi invocada, incluindo ID de usuário e locatário, juntamente com ID de chat ou IDs de canal e equipe.

Receber solicitações de usuário

Quando um usuário executa uma consulta, o Microsoft Teams envia ao seu serviço um objeto padrão do Bot Framework Activity . Seu serviço deve executar sua lógica para um Activity que foi type definido como invoke e name definido como um tipo com composeExtensions suporte, conforme mostrado na tabela a seguir.

Além das propriedades de atividade padrão do bot, o conteúdo contém os seguintes metadados de solicitação:

Nome da propriedade Objetivo
type Tipo de solicitação; deve ser invoke.
name Tipo de comando que é emitido para o serviço. Atualmente, há suporte para os seguintes tipos:
composeExtension/query
composeExtension/querySettingUrl
composeExtension/setting
composeExtension/selectItem
composeExtension/queryLink
from.id ID do usuário que enviou a solicitação.
from.name Nome do usuário que enviou a solicitação.
from.aadObjectId Microsoft Entra ID do objeto do usuário que enviou a solicitação.
channelData.tenant.id Microsoft Entra ID do locatário.
channelData.channel.id ID do canal (se a solicitação foi feita em um canal).
channelData.team.id ID da equipe (se a solicitação foi feita em um canal).
clientInfo Metadados opcionais sobre o software cliente usado para enviar a mensagem de um usuário. A entidade pode conter duas propriedades:
O country campo contém o local detectado pelo usuário.
O platform campo descreve a plataforma de cliente de mensagens.
Para obter mais informações, consulteTipos de entidade não IRI : clientInfo.

Os parâmetros de solicitação são encontrados no objeto value, que inclui as seguintes propriedades:

Nome da propriedade Objetivo
commandId O nome do comando invocado pelo usuário, correspondendo a um dos comandos declarados no manifesto do aplicativo.
parameters Matriz de parâmetros: cada objeto de parâmetro contém o nome do parâmetro, juntamente com o valor do parâmetro fornecido pelo usuário.
queryOptions Parâmetros de paginação:
skip: contagem de ignorar para esta consulta
count: número de elementos a serem retornados

Exemplo de solicitação

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

Como alternativa (ou além disso) para pesquisar seu serviço externo, você pode usar uma URL inserida na caixa de mensagens de composição para consultar seu serviço e retornar um cartão. Na captura de tela abaixo, um usuário coleu uma URL para um item de trabalho no Azure DevOps, que a extensão da mensagem resolveu em um cartão.

A captura de tela mostra o exemplo de desenrolamento de link.

Para permitir que sua extensão de mensagem interaja com links dessa maneira, primeiro você precisa adicionar a messageHandlers matriz ao manifesto do aplicativo como no exemplo:

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

Depois de adicionar o domínio para ouvir o manifesto do aplicativo, você precisará alterar o código do bot para responder à solicitação de invocação abaixo.

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

Se o aplicativo retornar vários itens, somente o primeiro será usado.

Responder a solicitações de usuário

Quando o usuário executa uma consulta, o Teams emite uma solicitação HTTP síncrona para seu serviço. Durante esse tempo, seu código tem 5 segundos para fornecer uma resposta HTTP à solicitação. Durante esse tempo, seu serviço pode executar outra pesquisa ou qualquer outra lógica de negócios necessária para atender à solicitação.

Seu serviço deve responder com os resultados correspondentes à consulta de usuário. A resposta deve indicar um código HTTP status de 200 OK e um objeto application/json válido com o seguinte corpo:

Nome da propriedade Objetivo
composeExtension Envelope de resposta de nível superior.
composeExtension.type Tipo de resposta. Há suporte para os seguintes tipos:
result: exibe uma lista de resultados da pesquisa
auth: solicita que o usuário se autentique
config: solicita que o usuário configure a extensão da mensagem
message: exibe uma mensagem de texto simples
composeExtension.attachmentLayout Especifica o layout dos anexos. Usado para respostas do tipo result.
Atualmente, há suporte para os seguintes tipos:
list: uma lista de objetos cartão que contêm campos de miniatura, título e texto
grid: uma grade de imagens de miniatura
composeExtension.attachments Matriz de objetos de anexo válidos. Usado para respostas do tipo result.
Atualmente, há suporte para os seguintes tipos:
application/vnd.microsoft.card.thumbnail
application/vnd.microsoft.card.hero
application/vnd.microsoft.teams.card.o365connector
application/vnd.microsoft.card.adaptive
composeExtension.suggestedActions Ações sugeridas. Usado para respostas do tipo auth ou config.
composeExtension.text Mensagem a ser exibida. Usado para respostas do tipo message.

Tipos e visualizações de cartão de resposta

Oferecemos suporte aos seguintes tipos de anexo:

Para obter mais informações, consulte Cartões para obter uma visão geral.

Para saber como usar os tipos de miniatura e cartão de herói, consulte Adicionar cartões e ações de cartão.

Para obter mais informações sobre o cartão do conector para Grupos do Microsoft 365, consulte Usando cartão de conector para Grupos do Microsoft 365.

A lista de resultados é exibida na interface do usuário do Microsoft Teams com uma visualização de cada item. A visualização é gerada de duas maneiras:

  • Usando a preview propriedade dentro do attachment objeto. O preview anexo só pode ser uma cartão hero ou miniatura.
  • Extraído das propriedades básicas title, texte image do anexo. Elas serão usadas somente se a preview propriedade não estiver definida e essas propriedades estiverem disponíveis.

Você pode exibir uma visualização de um cartão adaptável ou conector para Grupos do Microsoft 365 na lista de resultados simplesmente definindo sua propriedade de visualização. Isso não será necessário se os resultados já forem cartões de herói ou miniatura. Se você usar o anexo de visualização, ele deve ser um Hero ou uma Miniatura cartão. Se nenhuma propriedade de visualização for especificada, a visualização do cartão falhará e nada será exibido.

Exemplo de resposta

Este exemplo mostra uma resposta com dois resultados, misturando diferentes formatos de cartão: Conector para Grupos do Microsoft 365 e Adaptável. Embora você provavelmente queira manter um formato cartão em sua resposta, ele mostra como a preview propriedade de cada elemento da attachments coleção deve definir explicitamente uma visualização no formato hero ou miniatura, conforme descrito acima.

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

Consulta padrão

Se você definir initialRun como true no manifesto, o Microsoft Teams emitirá uma consulta "padrão" quando o usuário abrir a extensão da mensagem pela primeira vez. Seu serviço pode responder a essa consulta com um conjunto de resultados prepovoados. Isso pode ser útil para exibir, por exemplo, itens, favoritos ou qualquer outra informação que não dependa da entrada do usuário.

A consulta padrão tem a mesma estrutura que qualquer consulta de usuário regular, exceto com um parâmetro initialRun cujo valor de cadeia de caracteres é true.

Exemplo de solicitação para uma consulta padrão

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

Identifique o usuário

Cada solicitação aos seus serviços inclui a ID ofuscada do usuário que realizou a solicitação e o nome de exibição do usuário e Microsoft Entra ID do objeto.

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

Os id valores e aadObjectId são garantidos como o do usuário autenticado do Teams. Elas podem ser usadas como chaves para pesquisar credenciais ou qualquer estado armazenado em cache em seu serviço. Além disso, cada solicitação contém a Microsoft Entra ID do locatário do usuário, que pode ser usada para identificar a organização do usuário. Se aplicável, a solicitação também contém as IDs de equipe e de canal das quais a solicitação se originou.

Autenticação

Se o serviço exigir autenticação do usuário, você precisará entrar no usuário antes que o usuário possa usar a extensão da mensagem. Se você escreveu um bot ou uma guia que entra no usuário, esta seção deve ser familiar.

A sequência é a seguinte:

  1. O usuário emite uma consulta ou a consulta padrão é enviada automaticamente para seu serviço.
  2. Seu serviço verifica se o usuário foi autenticado pela primeira vez inspecionando a ID do usuário do Teams.
  3. Se o usuário não tiver se autenticado, envie de volta uma auth resposta com uma openUrl ação sugerida, incluindo a URL de autenticação.
  4. O cliente do Microsoft Teams inicia uma janela pop-up hospedando sua página da Web usando a URL de autenticação fornecida.
  5. Depois que o usuário entrar, você deve fechar a janela e enviar um "código de autenticação" para o cliente do Teams.
  6. Em seguida, o cliente do Teams reemissa a consulta para seu serviço, que inclui o código de autenticação passado na etapa 5. Seu serviço deve verificar se o código de autenticação recebido na etapa 6 corresponde ao da etapa 5, o que garante que um usuário mal-intencionado não tente falsificar ou comprometer o fluxo de entrada. Isso efetivamente "fecha o loop" para concluir a sequência de autenticação segura.

Responder com uma ação de entrada

Para solicitar que um usuário não autenticado entre, responda com uma ação sugerida do tipo openUrl que inclui a URL de autenticação.

Exemplo de resposta para uma ação de entrada

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

Observação

Para que a experiência de entrada seja hospedada em um pop-up do Teams, a parte de domínio da URL deve estar na lista de domínios válidos do aplicativo. Para obter mais informações, confira validDomains no esquema de manifesto.

Iniciar o fluxo de entrada

Sua entrada deve ser responsiva e adequada dentro de uma janela pop-up. Ela deve se integrar ao SDK do cliente JavaScript do Microsoft Teams, que usa a passagem de mensagens.

Assim como acontece com outras experiências inseridas em execução no Teams, seu código dentro da janela precisa primeiro chamar microsoftTeams.initialize(). Se o código executar um fluxo OAuth, você poderá passar a ID do usuário do Teams para sua janela, que poderá passá-la para a URL de URL de entrada do OAuth.

Concluir o fluxo de entrada

Quando a solicitação de entrada for concluída e redirecionada novamente para sua página, ela deverá executar as seguintes etapas:

  1. Gere um código de segurança. (Isso pode ser um número aleatório.) Você precisa armazenar esse código em cache em seu serviço, juntamente com as credenciais obtidas por meio da entrada, como tokens OAuth 2.0.
  2. Chamar microsoftTeams.authentication.notifySuccess e passar o código de segurança.

Neste ponto, a janela fecha e o controle é passado para o cliente do Teams. O cliente agora pode reemissar a consulta de usuário original, juntamente com o código de segurança na state propriedade. Seu código pode usar o código de segurança para pesquisar as credenciais armazenadas anteriormente para concluir a sequência de autenticação e, em seguida, concluir a solicitação do usuário.

Exemplo de solicitação reemitida

{
    "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"
}

Suporte ao SDK

.NET

Para receber e manipular consultas com o SDK do Construtor de Bots para .NET, você pode marcar para o invoke tipo de ação na atividade de entrada e, em seguida, usar o método auxiliar no pacote NuGet Microsoft.Bot.Connector.Teams para determinar se é uma atividade de extensão de mensagem.

Código de exemplo no .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

Código de exemplo no 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();

Confira também

Amostras de estrutura de bot