Exercício – Devolver dados de produtos de Microsoft Entra API protegida
Neste exercício, vai atualizar a extensão de mensagem para obter dados de uma API personalizada. Obtém dados da API personalizada com base na consulta do utilizador e devolve dados nos resultados da pesquisa ao utilizador.
Instalar e configurar o Proxy de Programador
Neste exercício, vai utilizar o Proxy Dev, uma ferramenta de linha de comandos que pode simular APIs. É útil quando quer testar a sua aplicação sem ter de criar uma API real.
Para concluir este exercício, tem de instalar a versão mais recente do Dev Proxy e transferir a predefinição de Proxy deV para este módulo.
A predefinição simula uma API CRUD (Criar, Ler, Atualizar, Eliminar) com um arquivo de dados dentro da memória, que está protegido por Microsoft Entra. Isto significa que pode testar a sua aplicação como se estivesse a chamar uma API real que requer autenticação.
Para transferir a predefinição, execute o seguinte comando no terminal:
devproxy preset get learn-copilot-me-plugin
Obter o valor de consulta do utilizador
Crie um método que obtenha o valor de consulta do utilizador pelo nome do parâmetro .
No Visual Studio e no projeto ProductsPlugin:
Na pasta Auxiliares , crie um novo ficheiro com o nome MessageExtensionHelpers.cs
No ficheiro, adicione o seguinte código:
using Microsoft.Bot.Schema.Teams; internal class MessageExtensionHelpers { internal static string GetQueryParameterValueByName(IList<MessagingExtensionParameter> parameters, string name) => parameters.FirstOrDefault(p => p.Name == name)?.Value as string ?? string.Empty; }
Save your changes
Em seguida, atualize o método OnTeamsMessagingExtensionQueryAsync para utilizar o novo método auxiliar.
Na pasta Procurar , abra SearchApp.cs
No método OnTeamsMessagingExtensionQueryAsync , substitua o seguinte código:
var text = query?.Parameters?[0]?.Value as string ?? string.Empty;
com
var text = MessageExtensionHelpers.GetQueryParameterValueByName(query.Parameters, "ProductName");
Mova o cursor para a variável de texto, utilize
Ctrl + R
,Ctrl + R
e mude o nome da variável para nameSave your changes
O método OnTeamsMessagingExtensionQueryAsync deverá agora ter o seguinte aspeto:
protected override async Task<MessagingExtensionResponse> OnTeamsMessagingExtensionQueryAsync(ITurnContext<IInvokeActivity> turnContext, MessagingExtensionQuery query, CancellationToken cancellationToken)
{
var userTokenClient = turnContext.TurnState.Get<UserTokenClient>();
var tokenResponse = await AuthHelpers.GetToken(userTokenClient, query.State, turnContext.Activity.From.Id, turnContext.Activity.ChannelId, connectionName, cancellationToken);
if (!AuthHelpers.HasToken(tokenResponse))
{
return await AuthHelpers.CreateAuthResponse(userTokenClient, connectionName, (Activity)turnContext.Activity, cancellationToken);
}
var name = MessageExtensionHelpers.GetQueryParameterValueByName(query.Parameters, "ProductName");
var card = await File.ReadAllTextAsync(Path.Combine(".", "Resources", "card.json"), cancellationToken);
var template = new AdaptiveCardTemplate(card);
return new MessagingExtensionResponse
{
ComposeExtension = new MessagingExtensionResult
{
Type = "result",
AttachmentLayout = "list",
Attachments = [
new MessagingExtensionAttachment
{
ContentType = AdaptiveCard.ContentType,
Content = JsonConvert.DeserializeObject(template.Expand(new { title = name })),
Preview = new ThumbnailCard { Title = name }.ToAttachment()
}
]
}
};
}
Obter dados da API personalizada
Para obter dados da API personalizada, tem de enviar o token de acesso no cabeçalho Autorização do pedido e anular a serialização da resposta num modelo que represente os dados do produto.
Em primeiro lugar, crie um modelo que represente os dados do produto que são devolvidos a partir da API personalizada.
No Visual Studio e no projeto ProductsPlugin:
Criar uma pasta denominada Modelos
Na pasta Modelos , crie um novo ficheiro com o nome Product.cs
No ficheiro, adicione o seguinte código:
using System.Text.Json.Serialization; internal class Product { [JsonPropertyName("productId")] public int Id { get; set; } [JsonPropertyName("imageUrl")] public string ImageUrl { get; set; } [JsonPropertyName("name")] public string Name { get; set; } [JsonPropertyName("category")] public string Category { get; set; } [JsonPropertyName("callVolume")] public int CallVolume { get; set; } [JsonPropertyName("releaseDate")] public string ReleaseDate { get; set; } }
Save your changes
Em seguida, crie uma classe de serviço que obtenha os dados do produto a partir da API personalizada.
Criar uma pasta denominada Serviços
Na pasta Serviços , crie um novo ficheiro com o nome ProductService.cs
No ficheiro, adicione o seguinte código:
using System.Net.Http.Headers; internal class ProductsService { private readonly HttpClient _httpClient; private readonly string _baseUri = "https://api.contoso.com/v1/"; internal ProductsService(string token) { _httpClient = new HttpClient(); _httpClient.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json")); _httpClient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", token); } internal async Task<Product[]> GetProductsByNameAsync(string name) { var response = await _httpClient.GetAsync($"{_baseUri}products?name={name}"); response.EnsureSuccessStatusCode(); var jsonString = await response.Content.ReadAsStringAsync(); return System.Text.Json.JsonSerializer.Deserialize<Product[]>(jsonString); } }
Save your changes
A classe ProductsService contém métodos para obter dados de produtos a partir da API personalizada. O construtor de classes utiliza um token de acesso como parâmetro e configura uma instância HttpClient com o token de acesso no cabeçalho Autorização.
Em seguida, atualize o método OnTeamsMessagingExtensionQueryAsync para utilizar a classe ProductsService para obter dados de produtos a partir da API personalizada.
Na pasta Procurar , abra SearchApp.cs
No método OnTeamsMessagingExtensionQueryAsync , adicione o seguinte código após a declaração da variável de nome para obter dados do produto a partir da API personalizada::
var productService = new ProductsService(tokenResponse.Token); var products = await productService.GetProductsByNameAsync(name);
Save your changes
Criar resultados de pesquisa
Agora que tem os dados do produto, pode incluí-lo nos resultados da pesquisa que são devolvidos ao utilizador.
Primeiro, vamos atualizar o modelo de Cartão Ajustável existente para apresentar as informações do produto.
Continuar no Visual Studio e no projeto ProductsPlugin:
Na pasta Recursos, mude o nome card.json para Product.json
Na pasta Recursos , crie um novo ficheiro com o nome Product.data.json. Este ficheiro contém dados de exemplo que o Visual Studio utiliza para gerar uma pré-visualização do modelo cartão ajustável.
No ficheiro, adicione o seguinte JSON:
{ "callVolume": 36, "category": "Enterprise", "imageUrl": "https://raw.githubusercontent.com/SharePoint/sp-dev-provisioning-templates/master/tenant/productsupport/source/Product%20Imagery/Contoso4.png", "name": "Contoso Quad", "productId": 1, "releaseDate": "2019-02-09" }
Save your changes
Na pasta Recursos , abra Product.json
No ficheiro, substitua os conteúdos pelo seguinte JSON:
{ "type": "AdaptiveCard", "$schema": "http://adaptivecards.io/schemas/adaptive-card.json", "version": "1.5", "body": [ { "type": "TextBlock", "text": "${name}", "wrap": true, "style": "heading" }, { "type": "TextBlock", "text": "${category}", "wrap": true }, { "type": "Container", "items": [ { "type": "Image", "url": "${imageUrl}", "altText": "${name}" } ], "minHeight": "350px", "verticalContentAlignment": "Center", "horizontalAlignment": "Center" }, { "type": "FactSet", "facts": [ { "title": "Call Volume", "value": "${formatNumber(callVolume,0)}" }, { "title": "Release Date", "value": "${formatDateTime(releaseDate,'dd/MM/yyyy')}" } ] } ] }
Save your changes
O modelo Cartão Ajustável utiliza expressões de enlace para apresentar as informações do produto. As expressões ${name}, ${category}, ${imageUrl}, ${callVolume} e ${releaseDate} são substituídas pelos valores correspondentes dos dados do produto. As funções de modelo formatNumber e formatDateTime são utilizadas para formatar os valores callVolume e releaseDate num número e data, respetivamente.
Tire um momento para explorar a pré-visualização do Cartão Ajustável no Visual Studio. A pré-visualização mostra o aspeto do modelo cartão ajustável quando os dados do produto estão vinculados ao modelo. Utiliza os dados de exemplo do ficheiro Product.data.json para gerar a pré-visualização.
Em seguida, atualize a propriedade validDomains no manifesto da aplicação para incluir o domínio raw.githubusercontent.com , para que as imagens no modelo Cartão Ajustável possam ser apresentadas no Microsoft Teams.
No projeto TeamsApp:
Na pasta appPackage , abra manifest.json
No ficheiro, adicione o domínio do GitHub à propriedade validDomains :
"validDomains": [ "token.botframework.com", "raw.githubusercontent.com", "${{BOT_DOMAIN}}" ],
Save your changes
Em seguida, atualize o método OnTeamsMessagingExtensionQueryAsync para criar uma lista de anexos que contêm as informações do produto.
No projeto ProductsPlugin:
Na pasta Procurar , abra SearchApp.cs
Atualize card.json para Product.json, para refletir a alteração no nome do ficheiro. Substitua o seguinte código:
var card = await File.ReadAllTextAsync(Path.Combine(".", "Resources", "card.json"), cancellationToken);
com
var card = await File.ReadAllTextAsync(Path.Combine(".", "Resources", "Product.json"), cancellationToken);
Adicione o seguinte código após a declaração da variável de modelo para criar uma lista de anexos:
var attachments = products.Select(product => { var content = template.Expand(product); return new MessagingExtensionAttachment { ContentType = AdaptiveCard.ContentType, Content = JsonConvert.DeserializeObject(content), Preview = new ThumbnailCard { Title = product.Name, Subtitle = product.Category, Images = [new() { Url = product.ImageUrl }] }.ToAttachment() }; }).ToList();
Atualize a instrução return para incluir a variável de anexos :
return new MessagingExtensionResponse { ComposeExtension = new MessagingExtensionResult { Type = "result", AttachmentLayout = "list", Attachments = attachments } };
Guardar alterações
Criar e atualizar recursos
Com tudo agora implementado, execute o processo Preparar Dependências de Aplicações do Teams para criar novos recursos e atualizar os existentes.
Continuar no Visual Studio:
- No Gerenciador de Soluções, clique com o botão direito do rato no projeto TeamsApp
- Expanda o menu Do Teams Toolkit , selecione Preparar Dependências de Aplicações do Teams
- Na caixa de diálogo Conta do Microsoft 365 , selecione Continuar
- Na caixa de diálogo Aprovisionar, selecione Aprovisionar
- Na caixa de diálogo de aviso Do Teams Toolkit , selecione Aprovisionar
- Na caixa de diálogo Informações do Teams Toolkit , selecione o ícone cruzado para fechar a caixa de diálogo
Executar e depurar
Com os recursos aprovisionados, inicie uma sessão de depuração para testar a extensão da mensagem.
Primeiro, inicie o Proxy de Programador para simular a API personalizada.
Abrir uma janela de terminal
Execute o seguinte comando para iniciar o Proxy de Programador:
devproxy --config-file "~appFolder/presets/learn-copilot-me-plugin/products-api-config.json"
Se lhe for pedido, aceite o aviso de certificado
Observação
Quando o Proxy de Programador está em execução, funciona como um proxy ao nível do sistema.
Em seguida, inicie uma sessão de depuração no Visual Studio:
Para iniciar uma nova sessão de depuração, prima F5 ou selecione Iniciar na barra de ferramentas
Aguarde até que seja aberta uma janela do browser e a caixa de diálogo de instalação da aplicação seja apresentada no cliente Web do Microsoft Teams. Se lhe for pedido, introduza as credenciais da sua conta do Microsoft 365.
Na caixa de diálogo de instalação da aplicação, selecione Adicionar
Abrir uma nova conversa do Microsoft Teams ou existente
Na área de composição de mensagens, selecione + para abrir o seletor de aplicações
Na lista de aplicações, selecione Produtos Contoso para abrir a extensão de mensagem
Na caixa de texto, introduza mark8
Aguarde até que a pesquisa seja concluída e que os resultados sejam apresentados
Na lista de resultados, selecione um resultado de pesquisa para incorporar uma card na caixa de mensagem de composição
Regresse ao Visual Studio e selecione Parar na barra de ferramentas ou prima Shift + F5 para parar a sessão de depuração. Além disso, encerre o Proxy de Programador com Ctrl + C.