Note
Access to this page requires authorization. You can try signing in or changing directories.
Access to this page requires authorization. You can try changing directories.
This article provides use cases for choosing a string (Raw ID) as a representation type of the CommunicationIdentifier type in Azure Communication Services SDKs. Follow this guidance to understand some use cases when you might want to choose a Raw ID over the CommunicationIdentifier derived types.
Use cases for choosing an identifier
A common task when implementing communication scenarios is to identify participants of conversations. When you're using Communication Services SDKs, CommunicationIdentifier
can uniquely identify these participants.
Using CommunicationIdentifier
has the following advantages:
- Provides good autocomplete in IDEs.
- Enables using a switch case by type to address different application flows.
- Enables restricting communication to specific types.
- Enables access to identifier details and uses them to call other APIs (such as the Microsoft Graph API) to provide a rich experience for communication participants.
In addition, the CommunicationIdentifier
and the derived types (MicrosoftTeamsUserIdentifier
, PhoneNumberIdentifier
, etc.) can be converted to its string representation (Raw ID) and restored from the string, making the following scenarios easier to implement:
- Store identifiers in a database and use them as keys.
- Use identifiers as keys in dictionaries.
- Implement intuitive REST CRUD APIs by using identifiers as key in REST API paths, instead of having to rely on POST payloads.
- Use identifiers as keys in declarative UI frameworks such as React to avoid unnecessary re-rendering.
Creating CommunicationIdentifier and retrieving Raw ID
You can create the CommunicationIdentifier
from a Raw ID. You can retrieve a Raw ID from a type derived from CommunicationIdentifier
. It removes the need for custom serialization methods that might take in only certain object properties and omit others. For example, the MicrosoftTeamsUserIdentifier
has multiple properties such as IsAnonymous
or Cloud
or methods to retrieve these values (depending on a platform). Using methods provided by Communication Identity SDK guarantees that the way of serializing identifiers remains canonical and consistent even if more properties are added.
Get Raw ID from CommunicationUserIdentifier:
public async Task GetRawId()
{
ChatMessage message = await ChatThreadClient.GetMessageAsync("678f26ef0c");
CommunicationIdentifier communicationIdentifier = message.Sender;
String rawId = communicationIdentifier.RawId;
}
Instantiate CommunicationUserIdentifier from a Raw ID:
public void CommunicationIdentifierFromGetRawId()
{
String rawId = "8:acs:bbbcbc1e-9f06-482a-b5d8-20e3f26ef0cd_45ab2481-1c1c-4005-be24-0ffb879b1130";
CommunicationIdentifier communicationIdentifier = CommunicationIdentifier.FromRawId(rawId);
}
You can find more platform-specific examples in the following article: Understand identifier types
Storing CommunicationIdentifier in a database
One of the typical jobs that may be required from you is mapping Azure Communication Services users to users coming from Contoso user database or identity provider. You can usually achieve this mapping by adding an extra column or field in the Contoso user DB or Identity Provider. However, given the characteristics of the Raw ID (stable, globally unique, and deterministic), you might want to use it as a primary key for the user storage.
Assuming a ContosoUser
is a class that represents a user of your application, and you want to save it along with a corresponding CommunicationIdentifier to the database. The original value for a CommunicationIdentifier
can come from the Communication Identity, Calling or Chat APIs or from a custom Contoso API but can be represented as a string
data type in your programming language no matter what the underlying type is:
public class ContosoUser
{
public string Name { get; set; }
public string Email { get; set; }
public string CommunicationId { get; set; }
}
You can access RawId
property of the CommunicationId
to get a string that can be stored in the database:
public void StoreToDatabase()
{
CommunicationIdentifier communicationIdentifier;
ContosoUser user = new ContosoUser()
{
Name = "John",
Email = "[email protected]",
CommunicationId = communicationIdentifier.RawId
};
SaveToDb(user);
}
If you want to get CommunicationIdentifier
from the stored Raw ID, you need to pass the raw string to FromRawId()
method:
public void GetFromDatabase()
{
ContosoUser user = GetFromDb("[email protected]");
CommunicationIdentifier communicationIdentifier = CommunicationIdentifier.FromRawId(user.CommunicationId);
}
It returns CommunicationUserIdentifier
, PhoneNumberIdentifier
, MicrosoftTeamsUserIdentifier
, or UnknownIdentifier
based on the identifier type.
Storing CommunicationIdentifier in collections
If your scenario requires working with several CommunicationIdentifier
objects in memory, you may want to store them in a collection (dictionary, list, hash set, etc.). A collection is useful, for example, for maintaining a list of call or chat participants. As the hashing logic relies on the value of a Raw ID, you can use CommunicationIdentifier
in collections that require elements to have a reliable hashing behavior.
The following examples demonstrate adding CommunicationIdentifier
objects to different types of collections and checking if they're contained in a collection by instantiating new identifiers from a Raw ID value.
The following example shows how you can use the Raw ID as a key in a dictionary to store user messages:
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];
}
As the hashing logic relies on the value of a Raw ID, you can use CommunicationIdentifier
itself as a key in a dictionary directly:
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")];
}
Hashing logic that relies on the value of a Raw ID, also enables you to add CommunicationIdentifier
objects to hash sets:
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"))){
//...
}
}
Another use case is using Raw IDs in mobile applications to identify participants. You can inject the participant view data for remote participant if you want to handle this information locally in the UI library without sending it to Azure Communication Services.
This view data can contain a UIImage that represents the avatar to render, and a display name they can optionally display instead.
Both the participant CommunicationIdentifier and Raw ID retrieved from it can be used to uniquely identify a remote participant.
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)")
}
}
}
}
Using Raw ID as key in REST API paths
When designing a REST API, you can have endpoints that either accept a CommunicationIdentifier
or a Raw ID string. If the identifier consists of several parts (like ObjectID, cloud name, etc. if you're using MicrosoftTeamsUserIdentifier
), you might need to pass it in the request body. However, using Raw ID enables you to address the entity in the URL path instead of passing the whole composite object as a JSON in the body. So that you can have a more intuitive REST CRUD API.
public async Task UseIdentifierInPath()
{
CommunicationIdentifier user = GetFromDb("[email protected]");
using HttpResponseMessage response = await client.GetAsync($"https://contoso.com/v1.0/users/{user.RawId}/profile");
response.EnsureSuccessStatusCode();
}
Extracting identifier details from Raw IDs.
Consistent underlying Raw ID enables:
- Deserializing to the right identifier type (based on which you can adjust the flow of your app).
- Extracting details of identifiers (such as an oid for
MicrosoftTeamsUserIdentifier
).
The example shows both benefits:
- The type enables you to decide where to take the avatar from.
- The decomposed details enable you to query the API in the right way.
public void ExtractIdentifierDetails()
{
ContosoUser user = GetFromDb("[email protected]");
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;
}
}
You can access properties or methods for a specific CommunicationIdentifier
type that is stored in a Contoso database in a form of a string (Raw ID).
Using Raw IDs as key in UI frameworks
You can use the Raw ID of an identifier as a key in UI components to track a certain user and avoid unnecessary re-rendering and API calls. In this example, we're changing the order of how users are rendered in a list. In the real world, we might want to show new users first or reorder users based on some condition (for example, hand raised). For the sake of simplicity, the following example just reverses the order in which the users are rendered.
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>;
});
Next steps
This article described how to:
- Correctly identify use cases for choosing a Raw ID
- Convert between Raw ID and different types of a
CommunicationIdentifier