你当前正在访问 Microsoft Azure Global Edition 技术文档网站。 如果需要访问由世纪互联运营的 Microsoft Azure 中国技术文档网站,请访问 https://docs.azure.cn

通信 SDK 中字符串标识符的用例

本文提供了在 Azure 通信服务 SDK 中选择字符串(原始 ID)作为 CommunicationIdentifier 类型的表示类型的用例。 遵循本指南将帮助你了解一些用例,当你可能想要通过 CommunicationIdentifier 派生类型选择原始 ID 时。

选择标识符的用例

实现通信方案时,常见的任务是识别对话参与者。 使用通信服务 SDK 时, CommunicationIdentifier 提供唯一标识这些参与者的功能。

CommunicationIdentifier 具有以下优势:

  • 在 IDE 中提供良好的自动完成。
  • 允许按类型使用开关事例来解决不同的应用程序流。
  • 允许将通信限制为特定类型。
  • 允许访问标识符详细信息,并使用它们调用其他 API(如 Microsoft Graph API),为通信参与者提供丰富的体验。

除此之外,CommunicationIdentifier 和派生类型(MicrosoftTeamsUserIdentifierPhoneNumberIdentifier等)可以转换为其字符串表示形式(原始 ID),并从字符串还原,使以下方案更易于实现:

  • 将标识符存储在数据库中,并将其用作密钥。
  • 在字典中将标识符用作键。
  • 通过在 REST API 路径中使用标识符作为密钥来实现直观的 REST CRUD API,而无需依赖 POST 有效负载。
  • 在声明性 UI 框架(如 React)中使用标识符作为键,以避免不必要的重新呈现。

创建 CommunicationIdentifier 并检索原始 ID

可以从原始 ID 创建 CommunicationIdentifier ,可以从派生自 CommunicationIdentifier 的类型检索原始 ID。 它消除了任何可能只采用某些对象属性并省略其他对象的自定义序列化方法的需求。 例如,具有 MicrosoftTeamsUserIdentifier 多个属性,例如 IsAnonymousCloud 方法来检索这些值(具体取决于平台)。 使用通信标识 SDK 提供的方法可确保序列化标识符的方式保持规范且一致,即使将添加更多属性也是如此。

从 CommunicationUserIdentifier 获取原始 ID:

public async Task GetRawId()
{
    ChatMessage message = await ChatThreadClient.GetMessageAsync("678f26ef0c");
    CommunicationIdentifier communicationIdentifier = message.Sender;
    String rawId = communicationIdentifier.RawId;
}

从原始 ID 实例化 CommunicationUserIdentifier:

public void CommunicationIdentifierFromGetRawId()
{
    String rawId = "8:acs:bbbcbc1e-9f06-482a-b5d8-20e3f26ef0cd_45ab2481-1c1c-4005-be24-0ffb879b1130";
    CommunicationIdentifier communicationIdentifier = CommunicationIdentifier.FromRawId(rawId);
}

可以在以下文章中找到更多特定于平台的示例: 了解标识符类型

将 CommunicationIdentifier 存储在数据库中

你可能需要的典型作业之一是将Azure 通信服务用户映射到来自 Contoso 用户数据库或标识提供者的用户。 这通常是通过在 Contoso 用户 DB 或标识提供者中添加额外的列或字段来实现的。 但是,鉴于原始 ID(稳定、全局唯一和确定性)的特征,还可以将其选择为用户存储的主键。

假设某个 ContosoUser 类表示应用程序的用户,并且你想要将其与相应的 CommunicationIdentifier 一起保存到数据库。 原始值 CommunicationIdentifier 可能来自通信标识、调用或聊天 API 或自定义 Contoso API,但无论基础类型是什么,都可以在编程语言中表示为 string 数据类型:

public class ContosoUser
{
    public string Name { get; set; }
    public string Email { get; set; }
    public string CommunicationId { get; set; }
}

可以访问 RawId 属性 CommunicationId 以获取可存储在数据库中的字符串:

public void StoreToDatabase()
{
    CommunicationIdentifier communicationIdentifier;

    ContosoUser user = new ContosoUser()
    {
        Name = "John",
        Email = "john@doe.com",
        CommunicationId = communicationIdentifier.RawId
    };
    SaveToDb(user);
}

如果要从存储的原始 ID 获取 CommunicationIdentifier ,需要将原始字符串传递给 FromRawId() 方法:

public void GetFromDatabase()
{
    ContosoUser user = GetFromDb("john@doe.com");
    CommunicationIdentifier communicationIdentifier = CommunicationIdentifier.FromRawId(user.CommunicationId);
}

它将返回CommunicationUserIdentifierPhoneNumberIdentifierMicrosoftTeamsUserIdentifier UnknownIdentifier基于标识符类型。

在集合中存储 CommunicationIdentifier

如果你的方案需要在内存中使用多个 CommunicationIdentifier 对象,则可能需要将它们存储在集合(字典、列表、哈希集等)中。 例如,集合可用于维护通话或聊天参与者的列表。 由于哈希逻辑依赖于原始 ID 的值,因此可以在需要元素具有可靠哈希行为的集合中使用 CommunicationIdentifier 。 以下示例演示如何通过将新标识符从原始 ID 值实例化新标识符,将 CommunicationIdentifier 对象添加到不同类型的集合中并检查。

以下示例演示如何在字典中将原始 ID 用作密钥来存储用户的消息:

public void StoreMessagesForContosoUsers()
{
    var communicationUser = new CommunicationUserIdentifier("8:acs:bbbcbc1e-9f06-482a-b5d8-20e3f26ef0cd_45ab2481-1c1c-4005-be24-0ffb879b1130");
    var teamsUserUser = new CommunicationUserIdentifier("45ab2481-1c1c-4005-be24-0ffb879b1130");
    
    // A dictionary with a CommunicationIdentifier as key might be used to store messages of a user.
    var userMessages = new Dictionary<string, List<Message>>
    {
        { communicationUser.RawId, new List<Message>() },
        { teamsUserUser.RawId, new List<Message>() },
    };

    // Retrieve messages for a user based on their Raw ID.
    var messages = userMessages[communicationUser.RawId];
}

由于哈希逻辑依赖于原始 ID 的值,因此可以直接在字典中将 CommunicationIdentifier 自身用作键:

public void StoreMessagesForContosoUsers()
{
    // A dictionary with a CommunicationIdentifier as key might be used to store messages of a user.
    var userMessages = new Dictionary<CommunicationIdentifier, List<Message>>
    {
        { new CommunicationUserIdentifier("8:acs:bbbcbc1e-9f06-482a-b5d8-20e3f26ef0cd_45ab2481-1c1c-4005-be24-0ffb879b1130"), new List<Message>() },
        { new MicrosoftTeamsUserIdentifier("45ab2481-1c1c-4005-be24-0ffb879b1130"), new List<Message>() },
    };

    // Retrieve messages for a user based on their Raw ID.
    var messages = userMessages[CommunicationIdentifier.FromRawId("8:acs:bbbcbc1e-9f06-482a-b5d8-20e3f26ef0cd_45ab2481-1c1c-4005-be24-0ffb879b1130")];
}

依赖于原始 ID 值的哈希逻辑还允许向哈希集添加 CommunicationIdentifier 对象:

public void StoreUniqueContosoUsers()
{
    // A hash set of unique users of a Contoso application.
    var users = new HashSet<CommunicationIdentifier>
    {
        new PhoneNumberIdentifier("+14255550123"),
        new UnknownIdentifier("28:45ab2481-1c1c-4005-be24-0ffb879b1130")
    };

    // Implement custom flow for a new communication user.
     if (users.Contains(CommunicationIdentifier.FromRawId("4:+14255550123"))){
        //...
     }
}

另一个用例是在移动应用程序中使用原始 ID 来标识参与者。 如果要在 UI 库中本地处理此信息而不将其发送到Azure 通信服务,则可以为远程参与者注入参与者视图数据。 此视图数据可以包含表示要呈现的头像的 UIImage,以及它们可以选择显示的显示名称。 从中检索到的参与者 CommunicationIdentifier 和 Raw ID 都可用于唯一标识远程参与者。

callComposite.events.onRemoteParticipantJoined = { identifiers in
  for identifier in identifiers {
    // map identifier to displayName
    let participantViewData = ParticipantViewData(displayName: "<DISPLAY_NAME>")
    callComposite.set(remoteParticipantViewData: participantViewData,
                      for: identifier) { result in
      switch result {
      case .success:
        print("Set participant view data succeeded")
      case .failure(let error):
        print("Set participant view data failed with \(error)")
      }
    }
  }
}    

在 REST API 路径中使用原始 ID 作为密钥

设计 REST API 时,可以具有接受原始 CommunicationIdentifier ID 字符串或原始 ID 字符串的终结点。 如果标识符由多个部分(如 ObjectID、云名称等)组成, MicrosoftTeamsUserIdentifier则可能需要在请求正文中传递它。 但是,使用原始 ID 可以寻址 URL 路径中的实体,而不是在正文中将整个复合对象作为 JSON 传递。 这样,就可以拥有更直观的 REST CRUD API。

public async Task UseIdentifierInPath()
{
    CommunicationIdentifier user = GetFromDb("john@doe.com");
    
    using HttpResponseMessage response = await client.GetAsync($"https://contoso.com/v1.0/users/{user.RawId}/profile");
    response.EnsureSuccessStatusCode();
}

从原始 ID 中提取标识符详细信息。

一致的基础原始 ID 允许:

  • 反序列化为正确的标识符类型(可基于该类型调整应用流)。
  • 提取标识符的详细信息(如 oid for MicrosoftTeamsUserIdentifier)。

此示例显示了这两个优点:

  • 此类型允许你决定从何处获取头像。
  • 分解的详细信息允许你以正确的方式查询 API。
public void ExtractIdentifierDetails()
{
    ContosoUser user = GetFromDb("john@doe.com");

    string rawId = user.CommunicationIdentifier;
    CommunicationIdentifier teamsUser = CommunicationIdentifier.FromRawId(rawId);
    switch (communicationIdentifier)
    {
        case MicrosoftTeamsUserIdentifier teamsUser:
            string getPhotoUri = $"https://graph.microsoft.com/v1.0/users/{teamsUser.UserId}/photo/$value";
            // ...
            break;
        case CommunicationIdentifier communicationUser:
            string getPhotoUri = GetAvatarFromDB(communicationUser.Id);
            // ...
            break;
    }
}

可以访问以字符串形式存储在 Contoso 数据库中的特定 CommunicationIdentifier 类型的属性或方法(原始 ID)。

在 UI 框架中使用原始 ID 作为密钥

可以使用标识符的原始 ID 作为 UI 组件中的密钥来跟踪特定用户,并避免不必要的重新呈现和 API 调用。 在此示例中,我们将更改用户在列表中呈现方式的顺序。 在现实世界中,我们可能希望首先显示新用户或根据某些条件重新订购用户(例如,举手)。 为简单起见,以下示例仅反转用户呈现的顺序。

import { getIdentifierRawId } from '@azure/communication-common';

function CommunicationParticipants() {
  const [users, setUsers] = React.useState([{ id: getIdentifierRawId(userA), name: "John" }, { id: getIdentifierRawId(userB), name: "Jane" }]);
  return (
    <div>
      {users.map((user) => (
      // React uses keys as hints while rendering elements. Each list item should have a key that's unique among its siblings. 
      // Raw ID can be utilized as a such key.
        <ListUser item={user} key={user.id} />
      ))}
      <button onClick={() => setUsers(users.slice().reverse())}>Reverse</button>
    </div>
  );
}

const ListUser = React.memo(function ListUser({ user }) {
  console.log(`Render ${user.name}`);
  return <div>{user.name}</div>;
});

后续步骤

本文介绍了如何执行以下操作:

  • 正确标识选择原始 ID 的用例
  • 在原始 ID 与不同类型的 CommunicationIdentifier 之间转换

要了解详细信息,你可能想要浏览以下快速入门指南: