When we think of implementing chat functionality, Facebook, WhatsApp, and a few other names come to mind. In the chat feature, we would look for functionalities like sending and receiving messages, creating groups, displaying unread chat messages, broadcasting messages to all contacts, etc.

Recently, we have integrated a chat feature into the CRM system using Azure Communication (ACS) Chat SDK. With ACS SDK, we can incorporate a chat feature into our application without being an expert in the underlying technology of real-time messaging. Instead, it provides basic functionalities to have real-time communication.

As we developed the Chat functionality, we ran into the below feature restrictions related to the chat SDK. So I thought it would be helpful to share the list of limitations and how you can overcome those.

Service Limits:

Here are a few size limits while creating a chat thread and adding participants.

Size Limit

There are several other service limits of Chat SDK explained in-depth here.

Feature limits:

The functionalities that are missing from the Chat SDK are listed below. However, some are still being thought about and might be featured in future releases.

  1. Deleting the chat thread for one of the participants.
  2. Archive/Pin chat thread for a user.
  3. GetThreads API does not return the unread count and the last message received data for the thread.
  4. Broadcast a message to every thread in which the user is a participant.
  5. Only text messaging is supported. Thus, to communicate multimedia, we must first store it in the cloud and then share the link.

Let's look at how we can put the aforementioned feature constraints into practice.

  1. Archive/Pin/Delete chat thread

    If we use the chat SDK inbuilt DeleteThread method it will delete the thread for every participant and can be done by the thread owner/creator. But in practice, participants might want to delete the thread just for themselves. We can achieve it by saving CommunicationUser and Threads data in DB and exposing some new APIs as mentioned below.

    1. Add CommunicationUser, ChatThreads, and ChatThreadParticipants tables in DB. We will save the thread statuses i.e Pin, Archive, and Delete in ChatThreadParticipants.
    2. Create new APIs for creating Communication Users, Chat Threads, and Add Participants. These APIs will internally call ACS Chat SDK methods and store details in DB.
    3. Create API to update statuses such as Archive/Pin/Delete on ChatThreadParticipants table.
    4. Instead of getting Threads directly from Chat SDK's GetThreads method, you need to expose a new API GetUserThreads to fetch threads data from the database.
    5. GetUserThreads API will return all threads except ones that have been deleted by sorting them according to the status field in ChatThreadParticipants.

    You can refer to this class diagram to better understand database schema.

    Database Class Diagram

    This way we can implement an Archive/Pin/Delete feature for the Chat Thread.

  2. Manage unread count and the last message received:

    Currently, the inbuilt GetThreads call returns the following response:

    {
      "value":
      [
        {
          "id": "19:uni01_zbnh3nt2dfuffezc3sox7dog7wfhk6y5qe2@thread.v2",
          "topic": "Chat with Samantha",
          "lastMessageReceivedOn": "2020-06-06T05:55:41.6460000Z"
        },
        {
          "id": "19:a0dfe5fc10e04a7f8d8a64d455f4196d@thread.v2",
          "topic": "Presentation Brainstorming",
          "lastMessageReceivedOn": "2020-06-06T05:55:41.6460000Z"
        },
      ]
    }
    

    In order to save UnreadCount, LastMsg, and LastMsgOn data in ChatThreadParticipants will need to handle ChatMessageReceivedInThread events emitted by the ACS chat service. To handle this event will need to do the following things:

    1. Create an event grid trigger Azure Function for handling events. It will update the thread's last message received details and unread count.

      [FunctionName("ChatEventHandler")]
      public async Task Run([EventGridTrigger] EventGridEvent e) {
        if (e.EventType == "Microsoft.Communication.ChatMessageReceivedInThread") {
          var data = e.Data.ToObjectFromJson<ChatMessageReceivedInThreadEventData>();
      
          using (var dataContext = DbFactory.Create()) {
            // Update Last message detail on thread
            var thread = dataContext.ReadWriteRepository<Communication_Chat_Threads>()
              .AsQueryable()
              .Where(x => x.ThreadId == model.ThreadId)
              .FirstOrDefault();
            if (thread != null) {
              thread.LastMessage = model.Message;
              thread.LastMessageOn = model.SendDate;                      
            }
            // Update UnreadCount for Participant 
            var threadParticpant = dataContext.ReadWriteRepository<Communication_Chat_Thread_Participants>()
              .AsQueryable()
              .Where(x => x.ThreadId == model.ThreadId && x.ParticipantId != model.SenderId)
              .FirstOrDefault();
            if (threadParticpant != null) {
              threadParticpant.UnreadCount = threadParticpant.UnreadCount + 1;
            }
            dataContext.Save();
          }
        }
      }
      
    2. To subscribe to chat events, go to the Events section of Azure Communication Services on the Azure Portal. As an event handler, add the above ChatEventHandler function endpoint.

    3. Create a new API to update the Unread count. This API will be called every time the user enters the chat thread, and the unread count will be set to 0.

    4. Expose a new API GetChatThreads to get the thread list from DB.

      [HttpGet]
      [Route("getChatThreads")]
      public HttpResponseMessage GetChatThreads([FromUri]ChatThreadFilterViewModel filter {
          filter.UserId = CurrentUserServices.UserId;
          var threads = CommunicationChatWorkerServices.GetUserThreads(filter);          
          return Request.CreateResponse(HttpStatusCode.OK, threads);
      }
      

    GetUserThreads will fetch data from the database as per our requirement.

  3. Broadcast Messaging:

    Implementing the broadcast functionality is relatively simple since thread details and communication user information are maintained in a database. To do this, we must provide an API endpoint to broadcast messages to the threads in which the user is a participant. This API will utilize the chat SDKs SendMessage method.

So this is one of the ways, we can implement the aforementioned feature limitations by keeping track of CommunicationUser, ChatThread, and ParticipantDetails in the database.

I hope the article was helpful. You can find more articles on implementing Azure Chat SDK here.

Thank you for sticking out till the end. Happy coding!