共用方式為


使用 UI 庫和 Azure Blob 儲存體在聊天中加入檔案分享

Important

此 Azure 通訊服務功能目前處於預覽狀態。 預覽中的功能可供公開使用,而且可供所有新的和現有的Microsoft客戶使用。

提供的預覽 API 和 SDK 並無服務等級協定。 建議您不要將其用於生產工作負載。 某些功能可能不受支援,或功能可能會受到限制。

如需詳細資訊,請參閱 Azure 預覽版Microsoft補充使用規定

在 Azure 通訊服務聊天中,我們可以在通訊使用者之間啟用檔案共用。 Azure 通訊服務聊天與 Teams 互作性聊天或 Interop 聊天不同。 如果您想要在 Interop 聊天中啟用檔案共用,請參閱 在 Teams 互作性聊天中新增與 UI 連結庫的檔案共用

本文說明如何設定 Azure 通訊服務 UI 連結庫聊天複合,以啟用檔案共用。 UI 圖書館聊天組合件提供一組豐富的元件及 UI 控件,我們可用於檔案分享。 我們將使用 Azure Blob 儲存體來儲存透過聊天對話共用的檔案。

Important

Azure 通訊服務不提供檔案儲存體服務。 您必須使用自己的檔案儲存體服務進行檔案共用。 本教學課程說明如何使用 Azure Blob 記憶體。

下載程式碼

請在UI程式庫範例 - 使用UI聊天組件進行檔案共用中取得本教學課程的完整程式碼。 如果您想要使用 UI 元件來使用檔案共用,請參閱 UI 連結 庫範例 - 使用 UI 元件共用檔案

Prerequisites

若要使用本文,您必須知道如何設定和執行複合式聊天。 如需如何設定及執行聊天複合的詳細資訊,請參閱 ChatComposite 教學課程

Overview

UI 程式庫聊天複合項目可讓開發人員將 URL 傳遞至透過 Azure 通訊服務聊天服務傳送的託管檔案,藉此支援檔案共用。 UI 程式庫會轉譯附加的檔案,並支援多個延伸模組,以設定所傳送檔案的外觀和風格。 更具體地說,其支援下列功能:

  1. 附加檔案按鈕,以透過OS檔案選擇器挑選檔案。
  2. 設定允許的副檔名。
  3. 啟用/停用多重上傳。
  4. 各種檔案類型的檔案圖示。
  5. 具有進度指標的檔案上傳/下載卡片。
  6. 能夠動態驗證每個檔案上傳並在 UI 上顯示錯誤。
  7. 能夠在傳送之前取消上傳並移除上傳的檔案。
  8. 在 MessageThread 中檢視已上傳的檔案,加以下載。 允許非同步下載。

下圖顯示上傳和下載檔案共用案例的一般流程。 標示為 Client Managed 的區段顯示了開發人員需要實作的基本構件。

檔案共用一般流程

使用 Azure Blob 設定檔案儲存體

您可以遵循使用 Azure 函式將檔案上傳至 Azure Blob 記憶體 教學課程,以撰寫檔案共用所需的後端程式代碼。

實作之後,您可以在 handleAttachmentSelection 函式內呼叫此 Azure 函式,以將檔案上傳至 Azure Blob 儲存體。 針對本教學課程的其餘部分,我們假設您使用先前連結的 Azure Blob 記憶體教學課程產生函式。

保護您的 Azure Blob 儲存體容器

本文假設您的 Azure Blob 記憶體容器可讓您公開存取您上傳的檔案。 不建議將 Azure 儲存體容器公開給實際生產應用程式使用。

若要下載檔案,請上傳至 Azure Blob 記憶體。 然後,您可以使用共用存取簽章(SAS)。 共用存取簽章 (SAS) 可提供您儲存體帳戶中資源的安全委派存取權。 使用 SAS 時,控制用戶端存取資料的方式更為精細。

可下載的 GitHub 範例 示範如何使用 SAS 來建立 Azure 記憶體內容的 SAS URL。 此外,您可以 深入瞭解 SAS

UI 程式庫需要設定 React 環境。 接下來我們會這麼做。 如果您已有 React 應用程式,可以跳過這一節。

設定 React 應用程式

本快速入門使用 create-react-app 範本。 如需詳細資訊,請參閱: 開始使用 React


npx create-react-app ui-library-quickstart-composites --template typescript

cd ui-library-quickstart-composites

在此程序結束時,資料夾 ui-library-quickstart-composites 內應該會有完整的應用程式。 在本快速入門中,我們會修改 src 資料夾內的檔案。

安裝這個套件

使用命令 npm install 來安裝適用於 JavaScript 的最新 Beta 版 Azure 通訊服務 UI 程式庫。


npm install @azure/communication-react@1.28.0-beta.2

@azure/communication-react 會將核心 Azure 通訊服務指定為 peerDependencies,以便您盡可能一致地從應用程式中的核心程式庫使用 API。 您也需要安裝下列程式庫:


npm install @azure/communication-calling@1.36.1-beta.1
npm install @azure/communication-chat@1.6.0-beta.7

建立 React 應用程式

我們將執行下列命令,藉以測試「建立 React 應用程式」安裝:


npm run start

設定聊天複合項目以啟用檔案共用

您必須為初始化聊天複合項目所需的兩個通用變數替換變數值。

App.tsx

import { initializeFileTypeIcons } from '@fluentui/react-file-type-icons';
import {
  ChatComposite,
  AttachmentUploadTask,
  AttachmentUploadOptions,
  AttachmentSelectionHandler,
  fromFlatCommunicationIdentifier,
  useAzureCommunicationChatAdapter
} from '@azure/communication-react';
import React, { useMemo } from 'react';

function App(): JSX.Element {
  initializeFileTypeIcons();

  // Common variables
  const endpointUrl = 'INSERT_ENDPOINT_URL';
  const userId = ' INSERT_USER_ID';
  const displayName = 'INSERT_DISPLAY_NAME';
  const token = 'INSERT_ACCESS_TOKEN';
  const threadId = 'INSERT_THREAD_ID';

  // We can't even initialize the Chat and Call adapters without a well-formed token.
  const credential = useMemo(() => {
    try {
      return new AzureCommunicationTokenCredential(token);
    } catch {
      console.error('Failed to construct token credential');
      return undefined;
    }
  }, [token]);

  // Memoize arguments to `useAzureCommunicationChatAdapter` so that
  // a new adapter is only created when an argument changes.
  const chatAdapterArgs = useMemo(
    () => ({
      endpoint: endpointUrl,
      userId: fromFlatCommunicationIdentifier(userId) as CommunicationUserIdentifier,
      displayName,
      credential,
      threadId
    }),
    [userId, displayName, credential, threadId]
  );
  const chatAdapter = useAzureCommunicationChatAdapter(chatAdapterArgs);

  if (chatAdapter) {
    return (
      <>
        <div style={containerStyle}>
          <ChatComposite
            adapter={chatAdapter}
            options={{
              attachmentOptions: {
                uploadOptions: uploadOptions,
                downloadOptions: downloadOptions,
              }
            }} />
        </div>
      </>
    );
  }
  if (credential === undefined) {
    return <h3>Failed to construct credential. Provided token is malformed.</h3>;
  }
  return <h3>Initializing...</h3>;
}

const uploadOptions: AttachmentUploadOptions = {
  // default is false
  disableMultipleUploads: false,
  // define mime types
  supportedMediaTypes: ["image/jpg", "image/jpeg"]
  handleAttachmentSelection: attachmentSelectionHandler,
}

const attachmentSelectionHandler: AttachmentSelectionHandler = async (uploadTasks) => {
  for (const task of uploadTasks) {
    try {
      const uniqueFileName = `${v4()}-${task.file?.name}`;
      const url = await uploadFileToAzureBlob(task);
      task.notifyUploadCompleted(uniqueFileName, url);
    } catch (error) {
      if (error instanceof Error) {
        task.notifyUploadFailed(error.message);
      }
    }
  }
}

const uploadFileToAzureBlob = async (uploadTask: AttachmentUploadTask) => {
  // You need to handle the file upload here and upload it to Azure Blob Storage.
  // This is how you can configure the upload
  // Optionally, you can also update the file upload progress.
  uploadTask.notifyUploadProgressChanged(0.2);
  return {
    url: 'https://sample.com/sample.jpg', // Download URL of the file.
  };
}

設定上傳方法以使用 Azure Blob 儲存體

若要啟用 Azure Blob 儲存體上傳,我們要修改先前使用下列程式碼宣告的 uploadFileToAzureBlob 方法。 您需要更換 Azure 函式的資訊來上傳檔案。

App.tsx

const uploadFileToAzureBlob = async (uploadTask: AttachmentUploadTask) => {
  const file = uploadTask.file;
  if (!file) {
    throw new Error("uploadTask.file is undefined");
  }

  const filename = file.name;
  const fileExtension = file.name.split(".").pop();

  // Following is an example of calling an Azure Function to handle file upload
  // The https://learn.microsoft.com/azure/developer/javascript/how-to/with-web-app/azure-function-file-upload
  // tutorial uses 'username' parameter to specify the storage container name.
  // the container in the tutorial is private by default. To get default downloads working in
  // this sample, you need to change the container's access level to Public via Azure portal.
  const username = "ui-library";

  // You can get function url from the Azure portal:
  const azFunctionBaseUri = "<YOUR_AZURE_FUNCTION_URL>";
  const uri = `${azFunctionBaseUri}&username=${username}&filename=${filename}`;

  const formData = new FormData();
  formData.append(file.name, file);

  const response = await axios.request({
    method: "post",
    url: uri,
    data: formData,
    onUploadProgress: (p) => {
      // Optionally, you can update the file upload progress.
      uploadTask.notifyUploadProgressChanged(p.loaded / p.total);
    },
  });

  const storageBaseUrl = "https://<YOUR_STORAGE_ACCOUNT>.blob.core.windows.net";

  return {
    url: `${storageBaseUrl}/${username}/${filename}`,
  };
};

錯誤處理

上傳失敗時,UI 程式庫聊天複合項目會顯示錯誤訊息。

檔案上傳錯誤列

以下是示範如何因大小驗證錯誤而無法上傳的範例程式代碼:

App.tsx

import { AttachmentSelectionHandler } from from '@azure/communication-react';

const attachmentSelectionHandler: AttachmentSelectionHandler = async (uploadTasks) => {
  for (const task of uploadTasks) {
    if (task.file && task.file.size > 99 * 1024 * 1024) {
      // Notify ChatComposite about upload failure.
      // Allows you to provide a custom error message.
      task.notifyUploadFailed('File too big. Select a file under 99 MB.');
    }
    ...
  }
}

export const attachmentUploadOptions: AttachmentUploadOptions = {
  handleAttachmentSelection: attachmentSelectionHandler
};

檔案下載 - 進階使用

預設情況下,UI 程式庫會開啟一個新的索引標籤,指向您在點擊後notifyUploadCompleted設定的 URL。 或者,您可以透過actionsForAttachment使用自定義邏輯來處理附件下載。 讓我們看看範例。

App.tsx

import { AttachmentDownloadOptions } from "communication-react";

const downloadOptions: AttachmentDownloadOptions = {
  actionsForAttachment: handler
}

const handler = async (attachment: AttachmentMetadata, message?: ChatMessage) => {
   // here we are returning a static action for all attachments and all messages
   // alternately, you can provide custom menu actions based on properties in `attachment` or `message` 
   return [defaultAttachmentMenuAction];
};

const customHandler = = async (attachment: AttachmentMetadata, message?: ChatMessage) => {
  const extension = attachment.name.split(".").pop() || "";
   if (extension === "pdf") {
    return [
      {
        title: "Custom button",
        icon: (<i className="custom-icon"></i>),
        onClick: () => {
          return new Promise((resolve, reject) => {
              // custom logic here
              window.alert("custom button clicked");
              resolve();
              // or to reject("xxxxx") with a custom message
          })
        }
      },
      defaultAttachmentMenuAction
    ];
  } else if (message?.senderId === "user1") {
    return [
      {
        title: "Custom button 2",
        icon: (<i className="custom-icon-2"></i>),
        onClick: () => {
          return new Promise((resolve, reject) => {
            window.alert("custom button 2 clicked");
            resolve();
          })
        }
      },
      // you can also override the default action partially
      {
        ...defaultAttachmentMenuAction,
        onClick: () => {
          return new Promise((resolve, reject) => {
            window.alert("default button clicked");
            resolve();
          })
        }
      }
    ];
  }
}

如果在下載過程中出現任何問題並且需要通知用戶,您可以在throw函式中使用onClick顯示錯誤訊息。 然後訊息會顯示在 [聊天複合] 頂端的錯誤列中。

顯示 [檔案下載錯誤] 的檔案下載錯誤

清除資源

如果您想要清除並移除通訊服務訂用帳戶,您可以刪除資源或資源群組。 刪除資源群組也會刪除與其相關聯的任何其他資源。 您可以深入瞭解如何清除 Azure 通訊服務資源和清除 Azure 函式資源

後續步驟