Search code examples
c#botframework

Set time of Activity.Typing animation


I'm trying to create some animation during the time when I fetch the data from a server. "Typing" activity seems to be reasonable but it works only for ~4 seconds :

Activity reply = activity.CreateReply();
reply.Type = ActivityTypes.Typing;
reply.Text = null;
ConnectorClient connector = new ConnectorClient(new Uri(activity.ServiceUrl));
await connector.Conversations.ReplyToActivityAsync(reply);

I was trying to do async listening:

while (!_fetchEnded)
{
   await connector.Conversations.ReplyToActivityAsync(reply);
   Thread.Sleep(3000);
}

But bot it creates laggy behaviour. Is there a possibility to set the duration of "typing" activity or another way around to prevent turning the typing on and off?


Solution

  • Typing is displayed only a few seconds by default. You can force the display typing indicator longer by sending again typing events at a lower frequency.

    Implementation example, where it will send events every 2 seconds, for 30 seconds max:

    public async Task<HttpResponseMessage> Post([FromBody]Microsoft.Bot.Connector.Activity activity, CancellationToken token)
    {
        // Send Typing messages
        var typingCancellation = new CancellationTokenSource(TimeSpan.FromSeconds(30));
        var typingTask = SendTypingActivityUntilCancellation(activity, TimeSpan.FromSeconds(2), typingCancellation.Token);
    
        try
        {
            // Activity treatment
            if (activity.Type == ActivityTypes.Message)
            {
                // ...
            }
            else if (activity.Type == ActivityTypes.Event && activity.ChannelId == ChannelEnum.directline.ToString())
            {
                // ...
            }
    
            typingCancellation.Cancel();
            await typingTask;
            return Request.CreateResponse(HttpStatusCode.OK);
        }
        catch (Exception e)
        {
            typingCancellation.Cancel();
            await typingTask;
            return Request.CreateResponse(HttpStatusCode.InternalServerError);
        }
    }
    
    public async Task SendTypingActivityUntilCancellation(Activity activity, TimeSpan period, CancellationToken cancellationtoken)
    {
        try
        {
            var connector = new ConnectorClient(new Uri(activity.ServiceUrl));
            Activity isTypingReply = activity.CreateReply();
            isTypingReply.Type = ActivityTypes.Typing;
    
            do
            {
                if (cancellationtoken.IsCancellationRequested == false)
                {
                    await connector.Conversations.ReplyToActivityAsync(isTypingReply);
                }
    
                // Check again if token has not been canceled during the reply delay
                if (cancellationtoken.IsCancellationRequested == false)
                {
                    await Task.Delay(period);
                }
            }
            while (cancellationtoken.IsCancellationRequested == false);
        }
        catch (OperationCanceledException)
        {
            //nothing to do.
        }
    }