Teilen über


Tutorial: Aktivieren der Dateianlagenunterstützung in Ihrer Chat-App

Das Chat SDK arbeitet nahtlos mit Microsoft Teams im Kontext einer Besprechung zusammen. Nur ein Teams-Benutzer kann Dateianlagen an einen Azure Communication Services-Benutzer senden. Azure Communication Services-Benutzer:innen können keine Dateianlagen an Teams-Benutzer:innen senden. Die aktuellen Funktionen finden Sie unter Teams-Interop-Chat.

Hinzufügen von Unterstützung für Dateianlagen

Das Chat SDK stellt die previewUrl-Eigenschaft für jede Dateianlage bereit. Insbesondere stellt previewUrl eine Verknüpfung mit einer Webseite in SharePoint bereit, über die Benutzer:innen den Inhalt der Datei anzeigen, die Datei bearbeiten und sie herunterladen können, sofern Ihre Berechtigung dies zulässt.

Mit diesem Feature sind einige Einschränkungen verbunden:

  • Der Teams-Administrator des Mandanten des Absenders kann Richtlinien durchsetzen, die dieses Feature einschränken oder vollständig deaktivieren. Beispielsweise können Teams-Administrator:innen bestimmte Berechtigungen (z. B. Anyone) deaktivieren, was dazu führen kann, dass auf die Dateianlage-URL (previewUrl) nicht zugegriffen werden kann.

  • Derzeit werden nur diese beiden Dateiberechtigungen unterstützt:

    • Anyone
    • People you choose (mit E-Mail-Adressen)

    Teilen Sie Ihren Teams-Benutzer:innen mit, dass alle anderen Berechtigungen (z. B. People in your organization) nicht unterstützt werden. Ihre Teams-Benutzer:innen sollten nach dem Hochladen der Datei auf ihren Teams-Client sicherstellen, dass die Standardberechtigung unterstützt wird.

  • Die direkte Download-URL (url) wird nicht unterstützt.

Neben regulären Dateien (mit AttachmentType von file) bietet das Chat SDK auch die AttachmentType-Eigenschaft von image. Azure Communication Services-Benutzer:innen können Bilder auf eine Weise anfügen, die das Verhalten widerspiegelt, wie der Microsoft Teams-Client Bildanlagen in Inlinebilder auf der Benutzeroberflächenebene konvertiert. Weitere Informationen finden Sie unter Behandeln von Bildanlagen.

Benutzer:innen von Azure Communication Services können Bilder über Von diesem Gerät hochladen hinzufügen. Dabei erfolgt das Rendern auf der Teams-Seite, und das Chat SDK gibt Anlagen wie image zurück. Bilder, die über Clouddateien anfügen hochgeladen werden, werden auf der Teams-Seite wie reguläre Dateien behandelt, daher gibt das Chat SDK solche Anlagen als file zurück.

Beachten Sie außerdem, dass Benutzer:innen von Azure Communication Services Dateien nur per Drag & Drop oder über die Befehle im Anlagemenü Von diesem Gerät hochladen und Clouddateien anfügen hochladen können. Bestimmte Typen von Nachrichten mit eingebetteten Medien (z. B. Videoclips, Audionachrichten und Wetterkarten) werden derzeit nicht unterstützt.

In diesem Tutorial wird beschrieben, wie Sie die Unterstützung von Dateianlagen mithilfe des Chat SDK von Azure Communication Services für JavaScript aktivieren.

Beispielcode

Den finalen Code dieses Tutorials finden Sie auf GitHub.

Voraussetzungen

Ziele

  • Rendern Sie die Dateianlage im Nachrichtenthread. Jede Dateianlagenkarte verfügt über eine Schaltfläche Öffnen.
  • Rendern Sie Bildanlagen als Inlinebilder.

Verarbeitung von Dateianlagen

Das Chat SDK für JavaScript gibt eine ChatAttachmentType-Eigenschaft von file für normale Dateianlagen und image für Inlinebilder in der Nachricht zurück.

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";

Der folgende JSON-Code ist ein Beispiel dafür, wie ChatAttachment für eine Bildanlage und eine Dateianlage aussehen könnte:

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

Kehren Sie nun zum Ereignishandler zurück, den Sie im vorherigen Schnellstart: Einbinden Ihrer Chat-App in eine Teams-Besprechung erstellt haben, um zusätzliche Logik zum Behandeln von Anlagen mit der attachmentType-Eigenschaft von file hinzuzufügen:

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>';
}

Fügen Sie CSS für die Anlagekarte hinzu:

  /* 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;
}

Das ist alles, was für die Verarbeitung von Dateianlagen erforderlich ist. Führen Sie als Nächstes den Code aus.

Ausführen des Codes

Für Webpack können Sie die webpack-dev-server-Eigenschaft verwenden, um Ihre App zu erstellen und auszuführen. Führen Sie den folgenden Befehl aus, um Ihren Anwendungshost auf einem lokalen Webserver zu bündeln:

npx webpack-dev-server --entry ./client.js --output bundle.js --debug --devtool inline-source-map

Oder:

npm start

Demo zu Dateianlagen

  1. Öffnen Sie Ihren Browser, und wechseln Sie zuhttp://localhost:8080/. Geben Sie die Besprechungs-URL und die Thread-ID ein.

  2. Senden Sie einige Dateianlagen vom Teams-Client.

    Screenshot des Teams-Clients mit einer gesendeten Nachricht mit drei Dateianlagen

  3. Sie sollten sehen, wie die neue Nachricht zusammen mit Dateianlagen gerendert wird.

    Screenshot einer Beispiel-App mit einer empfangenen eingehenden Nachricht mit drei Dateianlagen

Verarbeiten von Bildanlagen

Bildanlagen müssen anders behandelt werden als standardmäßige file-Anlagen. Bildanlagen weisen die attachmentType-Eigenschaft von image auf, die das Kommunikationstoken zum Abrufen der Vorschau oder von Bildern in voller Größe erfordert.

Bevor Sie fortfahren, führen Sie das Tutorial aus, in dem veranschaulicht wird, wie Sie die Inlinebildunterstützung in Ihrer Chat-App aktivieren. In diesem Lernprogramm wird beschrieben, wie Bilder abgerufen werden, die ein Kommunikationstoken im Anforderungsheader erfordern. Nachdem Sie das Bildblob erhalten haben, müssen Sie eine ObjectUrl-Eigenschaft erstellen, die auf dieses Blob verweist. Anschließend schleusen Sie diese URL in das src-Attribut jedes Inlinebilds ein.

Nachdem Sie nun mit der Funktionsweise von Inlinebildern vertraut sind, können Sie Bildanlagen wie normale Inlinebilder rendern.

Zunächst fügen Sie ein image-Tag in den Nachrichteninhalt ein, wenn eine Bildanlage vorhanden ist:

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

Verwenden Sie nun fetchPreviewImages() aus dem Tutorial: Aktivieren der Inlinebildunterstützung. Damit sollten Sie in der Lage sein, es ohne Änderungen zu verwenden:

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');
    });
}

Diese Funktion benötigt eine tokenString-Eigenschaft, daher benötigen Sie eine globale Kopie, die in init() initialisiert ist, wie im folgenden Codeschnipsel dargestellt:

var tokenString = '';

async function init() {
    ...
    const {
        token,
        expiresOn
    } = tokenResponse;
    
    tokenString = token;
    ...
}

Jetzt haben Sie Unterstützung für Bildanlagen. Führen Sie den Code aus, und sehen Sie ihn sich in Aktion an.

Demo zu Bildanlagen

  1. Senden Sie einige Bildanlagen vom Teams-Client.

    Screenshot des Teams-Clients mit einem Sendefeld und einer hochgeladenen Bildanlage

  2. Wenn Sie die Bildanlage senden, stellen Sie fest, dass sie aufseiten des Teams-Clients zu einem Inlinebild wird.

    Screenshot des Teams-Client mit einer Nachricht mit einem Bildanhang, die an den anderen Teilnehmenden gesendet wurde

  3. Kehren Sie zur Beispiel-App zurück, und vergewissern Sie sich, dass dasselbe Bild gerendert wird.

    Screenshot einer Beispiel-App mit einer eingehenden Nachricht mit einem gerenderten Inlinebild

In diesem Tutorial wird beschrieben, wie Sie die Unterstützung von Dateianlagen mithilfe des Chat SDK von Azure Communication Services für C# aktivieren.

In diesem Tutorial lernen Sie Folgendes:

  • Verarbeiten von Dateianlagen
  • Verarbeiten von Bildanlagen

Voraussetzungen

Beispielcode

Den finalen Code für dieses Tutorial finden Sie auf GitHub.

Verarbeitung von Dateianlagen

Das Chat SDK für C# gibt eine ChatAttachmentType-Eigenschaft von file für normale Dateianlagen und image für Inlinebilder in Nachrichten zurück.

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);
}


Der folgende JSON-Code ist ein Beispiel dafür, wie ChatAttachment für eine Bildanlage und eine Dateianlage aussehen könnte, wenn Sie Anforderungen von der Serverseite empfangen:

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

Kehren Sie nun zum Ereignishandler zurück, den Sie im vorherigen Schnellstart erstellt haben, um zusätzliche Logik zum Verarbeiten von Anlagen mit der ChatAttachmentType-Eigenschaft von file hinzuzufügen:


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}");
    }
}

Insbesondere erhalten Sie für jede Dateianlage die previewUrl-Eigenschaft und erstellen eine Liste der URLs in der for loop. Anschließend betten Sie die Zeichenfolge zusammen mit dem Inhalt der Chatnachricht ein.

Verarbeiten von Bildanlagen

Sie müssen Bildanlagen anders behandeln als standardmäßige file-Anlagen. Bildanlagen weisen die ChatAttachmentType-Eigenschaft von image auf, die das Kommunikationstoken zum Abrufen der Vorschau oder von Bildern in voller Größe erfordert.

Bevor Sie fortfahren, schließen Sie das Tutorial Aktivieren der Inlinebildunterstützung ab. Um Bildanlagen zu identifizieren, müssen Sie ermitteln, ob der Nachrichteninhalt die gleiche Bild-ID aus den Anlagen enthält.

bool isImageAttachment = message.Content.Message.Contains(x.Id);

Wenn dieses Flag TRUE ist, sollten Sie die Inlinebildlogik anwenden, um es zu rendern:

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);
}

Jetzt unterstützt Ihre App Bildanlagen.

Nächste Schritte