Create Bot for Microsoft Graph with DevOps 14: BotBuilder features – Intercept messages

Intercepting conversation between users and bot gives you opportunities to extend the bot without affecting current code. For example:

  • Log all conversations between users and the bot for analysis.
  • Inspect the incoming messages.

Though is it not pure intercept scenario from technology point of view, forward the conversation to human (hand-off scenario) is another interesting intercept scenario.

See here for more detail.

Log the conversations

Let’s add logging capability to O365Bot.

1. Add ActivityLogger.cs in the root and replace the code.

 using Microsoft.Bot.Builder.History;
using Microsoft.Bot.Connector;
using System.Diagnostics;
using System.Threading.Tasks;

namespace O365Bot.Services
{
    public class ActivityLogger : IActivityLogger
    {
        public async Task LogAsync(IActivity activity)
        {
            Debug.WriteLine($"From:{activity.From.Id} - To:{activity.Recipient.Id} - Message:{activity.AsMessageActivity()?.Text}");
        }
    }
}

2. Add following code in RegisterBotModules method of Global.asax.cs to register the created logger.

 builder.RegisterType<ActivityLogger>().AsImplementedInterfaces().InstancePerDependency();

Try with emulator

1. Before trying with emulator, change the code so that it won’t try to register the Microsoft Graph webhook if request comes from emulator by checking ChanneldId property.

 private async Task DoWork(IDialogContext context, IMessageActivity message)
{
    if (message.ChannelId != "emulator")
    {
        using (var scope = WebApiApplication.Container.BeginLifetimeScope())
        {
            var service = scope.Resolve<INotificationService>(new TypedParameter(typeof(IDialogContext), context));

            // Subscribe to Office 365 event change
            var subscriptionId = context.UserData.GetValueOrDefault<string>("SubscriptionId", "");
            if (string.IsNullOrEmpty(subscriptionId))
            {
                // Subscribe to Microsoft Graph Notification and get SubscriptionId
                subscriptionId = await service.SubscribeEventChange();
                context.UserData.SetValue("SubscriptionId", subscriptionId);
            }
            else
                await service.RenewSubscribeEventChange(subscriptionId);

            // Convert current message as ConversationReference.
            var conversationReference = message.ToConversationReference();

            // Map the ConversationReference to SubscriptionId of Microsoft Graph Notification.
            if (CacheService.caches.ContainsKey(subscriptionId))
                CacheService.caches[subscriptionId] = conversationReference;
            else
                CacheService.caches.Add(subscriptionId, conversationReference);
            // Store locale info as conversation info doesn't store it.
            if (!CacheService.caches.ContainsKey(message.From.Id))
                CacheService.caches.Add(message.From.Id, Thread.CurrentThread.CurrentCulture.Name);
        }
    }

    if (message.Text.Contains("get"))
        // Chain to GetEventDialog
        await context.Forward(new GetEventsDialog(), ResumeAfterDialog, message, CancellationToken.None);
    else if (message.Text.Contains("add"))
        // Chain to CreateEventDialog
        context.Call(new CreateEventDialog(), ResumeAfterDialog);
}

2. Run the bot by pressing F5, then connect to it from the emulator.

3. Send any message and check Output view in Visual Studio.

image

Where to store the date?

As it contains all information from users, you need to be careful where to store the data and how to use it. It should be depending on your company’s or organization’s policy. From technical point of view, I store is as JSON data to DocumentDB, then use PowerBI to analyze the data.

Unit Test

I don’t have any code to test at this point, but at least I register the logger for tests as well.

1. Add following code in RegisterBotModules method of UnitTest1.cs

 builder.RegisterType<ActivityLogger>().AsImplementedInterfaces().InstancePerDependency();

2. Compile the solution and run all unit tests.

Hand off scenario

Another interesting interruption scenario is hand off scenario, which let the user talk directly to human rather than bot.

One way to achieve this is to control the conversation at MessagesController level. For more detail, see the sample at https://github.com/tompaana/intermediator-bot-sample

Summery

Analyzing the bot usage is important. The developer portal gives you basic analysis result, but if you need more detailed information, you shall log all the conversation.

GitHub: https://github.com/kenakamu/BotWithDevOps-Blog-sample/tree/master/article14

Ken