Tutorial: habilitar o suporte de anexo de arquivo em seu aplicativo de Chat
O SDK de Chat funciona perfeitamente com o Microsoft Teams no contexto de uma reunião. Somente um usuário do Teams pode enviar anexos de arquivo para um usuário dos Serviços de Comunicação do Azure. Um usuário dos Serviços de Comunicação do Azure não pode enviar anexos de arquivo para um usuário do Teams. Para ver as funcionalidades atuais, confira Chat de interoperabilidade do Teams.
Adicionar suporte a anexos de arquivo
O SDK de Chat fornece a propriedade previewUrl
para cada anexo de arquivo. Especificamente, previewUrl
é um link para uma página da Web no SharePoint em que o usuário pode ver o conteúdo do arquivo, editá-lo e, se tiver permissão, baixar o arquivo.
Algumas restrições estão associadas a esse recurso:
O administrador do Teams do locatário do remetente pode impor políticas que limitam ou desabilitam totalmente esse recurso. Por exemplo, o administrador do Teams poderá desabilitar determinadas permissões (como
Anyone
), o que pode fazer com que as URLs de anexo de arquivo (previewUrl
) fiquem inacessíveis.Atualmente, só há suporte para duas permissões de arquivo:
Anyone
People you choose
(com endereço de email)
Permitir que o usuário do Teams saiba que não há suporte para todas as outras permissões (como
People in your organization
). Os usuários do Teams devem verificar se há suporte para a permissão padrão depois de carregarem o arquivo nos respectivos clientes do Teams.Não há suporte para a URL de download direto (
url
).
Além de arquivos comuns (com o AttachmentType
de file
), o SDK de Chat também fornece a propriedade AttachmentType
de image
. Os usuários dos Serviços de Comunicação do Azure podem anexar imagens de um jeito que imite o comportamento de um cliente do Microsoft Teams convertendo o anexo de imagem em imagens embutidas na camada da interface do usuário. Para obter mais informações, confira Tratar anexos de imagem.
Os usuários dos Serviços de Comunicação do Azure podem adicionar imagens por meio da opção Carregar deste dispositivo, que é renderizada no Teams. Portanto, o SDK de Chat retorna anexos como image
. Para imagens carregadas por meio da opção Anexar arquivos de nuvem, as imagens são tratadas como arquivos comuns no Teams. Portanto, o SDK de Chat retorna anexos como file
.
Observe também que os usuários dos Serviços de Comunicação do Azure só podem carregar arquivos por meio da funcionalidade do tipo "arrastar e soltar" ou por meio dos comandos do menu de anexos Carregar deste dispositivo e Anexar arquivos de nuvem. No momento, não há suporte para determinados tipos de mensagens com mídia inserida (como clipes de vídeo, mensagens de áudio e cartões meteorológicos).
Este tutorial descreve como habilitar o suporte a anexos de arquivo usando o SDK de Chat dos Serviços de Comunicação do Azure para JavaScript.
Código de exemplo
Encontre o código finalizado desse tutorial no GitHub.
Pré-requisitos
- Revisar o início rápido Ingressar seu aplicativo de Chat em uma reunião do Teams.
- Criar um recurso dos Serviços de Comunicação do Azure. Para obter mais informações, confira Criar um recurso dos Serviços de Comunicação do Azure. Você precisará registrar a cadeia de conexão para este tutorial.
- Organize uma reunião no Teams usando sua conta empresarial e tenha a URL da reunião pronta para uso.
- Use o SDK de Chat para JavaScript (@azure/communication-chat) 1.5.0 ou o mais recente. Para mais informações, confira a Biblioteca de clientes do chat de comunicação do Azure para JavaScript.
Metas
- Renderizar o anexo de arquivo no thread de mensagem. Cada cartão de anexo de arquivo tem um botão Abrir.
- Renderizar anexos de imagem como imagens embutidas.
Manipular anexos de arquivo
O SDK de Chat para JavaScript retorna uma propriedade ChatAttachmentType
de file
para anexos de arquivo comuns e image
para imagens embutidas em mensagens.
export interface ChatMessageReceivedEvent extends BaseChatMessageEvent {
/**
* Content of the message.
*/
message: string;
/**
* Chat message attachment.
*/
attachments?: ChatAttachment[];
...
}
export interface ChatAttachment {
/** Id of the attachment */
id: string;
/** The type of attachment. */
attachmentType: AttachmentType;
/** The name of the attachment content. */
name?: string;
/** The URL that is used to provide the original size of the inline images */
url?: string;
/** The URL that provides the preview of the attachment */
previewUrl?: string;
}
/** Type of supported attachments. */
export type ChatAttachmentType = "image" | "file" | "unknown";
Por exemplo, o seguinte JSON mostra o que ChatAttachment
pode parecer para um anexo de imagem e um anexo de arquivo:
"attachments": [
{
"id": "08a182fe-0b29-443e-8d7f-8896bc1908a2",
"attachmentType": "file",
"name": "business report.pdf",
"previewUrl": "https://contoso.sharepoint.com/:u:/g/user/h8jTwB0Zl1AY"
},
{
"id": "9d89acb2-c4e4-4cab-b94a-7c12a61afe30",
"attachmentType": "image",
"name": "Screenshot.png",
"url": "https://contoso.communication.azure.com/chat/threads/19:9d89acb29d89acb2@thread.v2/messages/123/images/9d89acb2-c4e4-4cab-b94a-7c12a61afe30/views/original?api-version=2023-11-15-preview",
"previewUrl": "https://contoso.communication.azure.com/chat/threads/19:9d89acb29d89acb2@thread.v2/messages/123/images/9d89acb2-c4e4-4cab-b94a-7c12a61afe30/views/small?api-version=2023-11-15-preview"
}
]
Agora, vamos voltar ao manipulador de eventos que você criou no Guia de Início Rápido: ingressar seu aplicativo de Chat em uma reunião do Teams e adicionar uma lógica extra para tratar anexos com a propriedade attachmentType
de file
:
chatClient.on("chatMessageReceived", (e) => {
console.log("Notification chatMessageReceived!");
// Check whether the notification is intended for the current thread
if (threadIdInput.value != e.threadId) {
return;
}
if (e.sender.communicationUserId != userId) {
renderReceivedMessage(e);
} else {
renderSentMessage(e.message);
}
});
async function renderReceivedMessage(event) {
messages += `<div class="container lighter"> ${event.message} </div>`;
messagesContainer.innerHTML = messages;
// Get the list of attachments and calls renderFileAttachments to construct a file attachment card
var attachmentHtml = event.attachments
.filter(attachment => attachment.attachmentType === "file")
.map(attachment => renderFileAttachments(attachment))
.join('');
messagesContainer.innerHTML += attachmentHtml;
}
function renderFileAttachments(attachment) {
var re = /(?:\.([^.]+))?$/;
var fileExtension = re.exec(attachment.name)[1];
return '<div class="attachment-container">' +
'<img class="attachment-icon" alt="attachment file icon" />' +
'<div>' +
'<p class="attachment-type">' + fileExtension + '</p>' +
'<p>' + attachment.name + '</p>' +
'<a href=' + attachment.previewUrl + ' target="_blank" rel="noreferrer">Open</a>' +
'</div>' +
'</div>';
}
Adicione um CSS ao cartão de anexo:
/* Let's make the chat popup scrollable */
.chat-popup {
...
max-height: 650px;
overflow-y: scroll;
}
.attachment-container {
overflow: hidden;
background: #f3f2f1;
padding: 20px;
margin: 0;
border-radius: 10px;
}
.attachment-container img {
width: 50px;
height: 50px;
float: left;
margin: 0;
}
.attachment-container p {
font-weight: 700;
margin: 0 5px 20px 0;
}
.attachment-container {
display: grid;
grid-template-columns: 100px 1fr;
margin-top: 5px;
}
.attachment-icon {
content: url("data:image/svg+xml;base64, ...");
}
.attachment-container a {
background-color: #dadada;
color: black;
font-size: 12px;
padding: 10px;
border: none;
cursor: pointer;
border-radius: 5px;
text-align: center;
margin-right: 10px;
text-decoration: none;
margin-top: 10px;
}
.attachment-container a:hover {
background-color: black;
color: white;
}
.attachment-type {
position: absolute;
color: black;
border: 2px solid black;
background-color: white;
margin-top: 50px;
font-family: sans-serif;
font-weight: 400;
padding: 2px;
text-transform: uppercase;
font-size: 8px;
}
Isso é tudo o que você precisa para tratar anexos de arquivo. Em seguida, vamos executar o código.
Executar o código
No caso do Webpack, você pode usar a propriedade webpack-dev-server
para criar e executar seu aplicativo. Execute o seguinte comando para empacotar o host de aplicativos em um servidor Web local:
npx webpack-dev-server --entry ./client.js --output bundle.js --debug --devtool inline-source-map
Ou:
npm start
Demonstração de anexo de arquivo
Abra o navegador e vá para
http://localhost:8080/
. Insira a URL da reunião e a ID do thread.Envie alguns anexos de arquivo a partir do cliente do Teams.
Você deverá ver a nova mensagem sendo renderizada junto com os anexos de arquivo.
Manipular anexos de imagem
Os anexos de imagem precisam ser tratados de maneira diferente dos anexos padrão file
. Os anexos de imagem têm a propriedadeattachmentType
de image
, o que exige que o token de comunicação recupere as imagens de versão prévia ou em tamanho real.
Antes de continuar, conclua o tutorial que demonstra como habilitar o suporte de imagem embutida no seu aplicativo de Chat. Este tutorial descreve como buscar imagens que exigem um token de comunicação no cabeçalho da solicitação. Depois de receber o blob da imagem, você precisará criar uma propriedade ObjectUrl
que aponte para esse blob. Em seguida, você injeta essa URL no atributo src
de cada imagem embutida.
Agora que você já se familiarizou com o funcionamento das imagens embutidas, poderá renderizar anexos de imagem como uma imagem embutida comum.
Primeiro, injete uma marca image
no conteúdo da mensagem sempre que houver um anexo de imagem:
async function renderReceivedMessage(event) {
messages += `<div class="container lighter"> ${event.message} </div>`;
messagesContainer.innerHTML = messages;
console.log(event);
// Filter out inline images from attachments
const imageAttachments = event.attachments?.filter(
(attachment) =>
attachment.attachmentType === "image" && !messages.includes(attachment.id)
);
// Inject image tag for all image attachments
var imageAttachmentHtml =
imageAttachments
.map((attachment) => renderImageAttachments(attachment))
.join("") ?? "";
messagesContainer.innerHTML += imageAttachmentHtml;
// Get list of attachments and calls renderFileAttachments to construct a file attachment card
var attachmentHtml =
event.attachments
?.filter((attachment) => attachment.attachmentType === "file")
.map((attachment) => renderFileAttachments(attachment))
.join("") ?? "";
messagesContainer.innerHTML += attachmentHtml;
// Fetch and render preview images
fetchPreviewImages(imageAttachments);
}
function renderImageAttachments(attachment) {
return `<img alt="image" src="" itemscope="png" id="${attachment.id}" style="max-width: 100px">`
}
Agora, vamos pegar o recurso de fetchPreviewImages()
emprestado do Tutorial: Habilitar o suporte à imagem embutida e usá-lo no estado em que se encontra, sem alterações:
function fetchPreviewImages(attachments) {
if (!attachments.length > 0) {
return;
}
Promise.all(
attachments.map(async (attachment) => {
const response = await fetch(attachment.previewUrl, {
method: 'GET',
headers: {
'Authorization': 'Bearer ' + tokenString,
},
});
return {
id: attachment.id,
content: await response.blob(),
};
}),
).then((result) => {
result.forEach((imageRef) => {
const urlCreator = window.URL || window.webkitURL;
const url = urlCreator.createObjectURL(imageRef.content);
document.getElementById(imageRef.id).src = url;
});
}).catch((e) => {
console.log('error fetching preview images');
});
}
Essa função precisa de uma propriedade tokenString
, portanto, você precisa ter uma cópia global inicializada em init()
, conforme mostrado no trecho de código a seguir:
var tokenString = '';
async function init() {
...
const {
token,
expiresOn
} = tokenResponse;
tokenString = token;
...
}
Agora você tem um suporte para anexo de imagem. Continue para executar o código e vê-lo em ação.
Demonstração de anexo de imagem
Envie alguns anexos de imagem a partir do cliente do Teams.
Depois de enviar o anexo de imagem, observe que ele se torna uma imagem embutida no cliente do Teams.
Volte ao aplicativo de exemplo e verifique se a mesma imagem está renderizada.
Este tutorial descreve como habilitar o suporte a anexos de arquivo usando o SDK dos Serviços de Comunicação do Azure de Chat para C#.
Neste tutorial, você aprenderá a:
- Manipular anexos de arquivo.
- Manipular anexos de imagem.
Pré-requisitos
- Revisar o início rápido Ingressar seu aplicativo de Chat em uma reunião do Teams.
- Crie um recurso dos Serviços de Comunicação do Azure, conforme descrito em Criar um recurso dos Serviços de Comunicação do Azure. Você precisará registrar a cadeia de conexão para este tutorial.
- Organize uma reunião no Teams usando sua conta empresarial e tenha a URL da reunião pronta para uso.
- Baixe o SDK de Chat para C# (@azure/communication-chat) 1.3.0 ou o mais recente. Para mais informações, confira a Biblioteca de clientes do Chat de Comunicação do Azure.
Código de exemplo
Encontre o código finalizado deste tutorial no GitHub.
Manipular anexos de arquivo
O SDK de Chat para C# retorna uma propriedade ChatAttachmentType
de file
para anexos de arquivo comuns e image
para imagens embutidas.
public readonly partial struct ChatAttachmentType : IEquatable<ChatAttachmentType>
{
private const string ImageValue = "image";
private const string FileValue = "file";
/// <summary> image. </summary>
public static ChatAttachmentType Image { get; } = new ChatAttachmentType(ImageValue);
/// <summary> file. </summary>
public static ChatAttachmentType File { get; } = new ChatAttachmentType(FileValue);
}
Por exemplo, o JSON a seguir mostra a aparência de ChatAttachment
para um anexo de imagem e um anexo de arquivo quando você recebe solicitações do lado do servidor:
"attachments": [
{
"id": "08a182fe-0b29-443e-8d7f-8896bc1908a2",
"attachmentType": "file",
"name": "business report.pdf",
"previewUrl": "https://contoso.sharepoint.com/:u:/g/user/h8jTwB0Zl1AY"
},
{
"id": "9d89acb2-c4e4-4cab-b94a-7c12a61afe30",
"attachmentType": "image",
"name": "Screenshot.png",
"url": "https://contoso.communication.azure.com/chat/threads/19:9d89acb29d89acb2@thread.v2/messages/123/images/9d89acb2-c4e4-4cab-b94a-7c12a61afe30/views/original?api-version=2023-11-15-preview",
"previewUrl": "https://contoso.communication.azure.com/chat/threads/19:9d89acb29d89acb2@thread.v2/messages/123/images/9d89acb2-c4e4-4cab-b94a-7c12a61afe30/views/small?api-version=2023-11-15-preview"
}
]
Agora, volte ao manipulador de eventos que você criou no guia de início rápido anterior e adicione uma lógica extra para tratar os anexos com a propriedadeChatAttachmentType
de file
:
await foreach (ChatMessage message in allMessages)
{
// Get message attachments that are of type 'file'
IEnumerable<ChatAttachment> fileAttachments = message.Content.Attachments.Where(x => x.AttachmentType == ChatAttachmentType.File);
var chatAttachmentFileUris = new List<Uri>();
foreach (var file in fileAttachments)
{
chatAttachmentFileUris.Add(file.PreviewUri);
}
// Build message list
if (message.Type == ChatMessageType.Html || message.Type == ChatMessageType.Text)
{
textMessages++;
var userPrefix = message.Sender.Equals(currentUser) ? "[you]:" : "";
var strippedMessage = StripHtml(message.Content.Message);
var chatAttachments = fileAttachments.Count() > 0 ? "[Attachments]:\n" + string.Join(",\n", chatAttachmentFileUris) : "";
messageList.Add(long.Parse(message.SequenceId), $"{userPrefix}{strippedMessage}\n{chatAttachments}");
}
}
Especificamente, para cada anexo de arquivo, obtemos a propriedade previewUrl
e construímos uma lista de URLs no for loop
. Em seguida, você insere a cadeia de caracteres junto com o conteúdo da mensagem de Chat.
Manipular anexos de imagem
Você precisa tratar os anexos de imagem de maneira diferente dos anexos de file
padrão. Os anexos de imagem têm a propriedade ChatAttachmentType
de image
, o que exige que o token de comunicação recupere as imagens de versão prévia ou em tamanho real.
Antes de continuar, termine o tutorial Habilitar suporte à imagem embutida. Para identificar os anexos de imagem, você precisa descobrir se o conteúdo da mensagem contém a mesma ID de imagem dos anexos.
bool isImageAttachment = message.Content.Message.Contains(x.Id);
Caso esse sinalizador seja verdadeiro, aplique a lógica de imagem embutida para renderizá-lo:
IEnumerable<ChatAttachment> imageAttachments = message.Content.Attachments.Where(x => x.AttachmentType == ChatAttachmentType.Image);
// Fetch image and render
var chatAttachmentImageUris = new List<Uri>();
foreach (ChatAttachment imageAttachment in imageAttachments)
{
client.DefaultRequestHeaders.Authorization = new System.Net.Http.Headers.AuthenticationHeaderValue("Bearer", communicationTokenCredential.GetToken().Token);
var response = await client.GetAsync(imageAttachment.PreviewUri);
var randomAccessStream = await response.Content.ReadAsStreamAsync();
await Dispatcher.RunAsync(CoreDispatcherPriority.Normal, async () =>
{
var bitmapImage = new BitmapImage();
await bitmapImage.SetSourceAsync(randomAccessStream.AsRandomAccessStream());
InlineImage.Source = bitmapImage;
});
chatAttachmentImageUris.Add(imageAttachment.PreviewUri);
}
Agora seu aplicativo já dá suporte a anexos de imagem.
Próximas etapas
- Saiba mais sobre como habilitar o suporte a imagens embutidas.
- Saiba mais sobre outros recursos de interoperabilidade com suporte.
- Confira nosso Exemplo de chat em destaque.
- Saiba mais sobre como o Chat funciona.