This sample demonstrates how to control a chatbot, built on the Microsoft Bot Framework, utilizing backchannel messages.
C# HTML ASP
Switch branches/tags
Nothing to show
Clone or download
Fetching latest commit…
Cannot retrieve the latest commit at this time.
Permalink
Failed to load latest commit information.
Documentation
RemoteControlBotControllerSample
RemoteControlBotSample
.gitignore
LICENSE
README.md
RemoteControlBotSample.sln

README.md

Remote Control Bot Sample

This sample demonstrates how to control a chatbot, built on the Microsoft Bot Framework, utilizing backchannel messages. The covering note (a blog post) for this sample is here: Remotely Controlled Bots. It is recommended to read that first to understand how the backchannel messages work.

Sample in action

Running and testing

  1. Clone or copy the repository
  2. Register a bot for this sample in the bot portal
    • Unfortunately registering and publishing the bot is the easiest way to get to test drive it, because the implementation is dependent on Direct Line
  3. Get the app ID and app password (a step in registration phase) and insert them into the Web.config
  4. Publish the bot (and insert the newly created endpoint to the bot portal)
  5. In the portal, activate Direct Line and get the first secret key
  6. Insert the secret key into Program.cs
  7. Say something to the bot so that it knows who you are (your virtual address), you can do this on any channel the bot is on or using emulator
    • If you don't say anything the bot won't know you and cannot notify you
  8. Run the console app (RemoteControlBotControllerSample)
  9. Enjoy your three notifications

Implementation

The implementation consists of roughly 3 different concepts:

  1. Backchannel receiver (implemented in this sample by NotificationsScorable, see PrepareAsync method)
  2. Notification type and handler (in Notifications folder)
  3. Message routing for delivering the notifications to (specific) users

How does it work?

Let's look at two scenarios. First, when the bot receives a normal message from the user:

  1. A user sends a message to the bot
    • The Microsoft Bot Framework translates this to an object called Activity, where its Text property will contain the message
  2. The received Activity instance is seemingly passed to the root dialog in MessagesController class
  3. Autofac checks for registered handlers at the previous step (step 2)
    • It will find two: MessageRouterScorable and NotificationsScorable
    • MessageRouterScorable always stores the sender and the receiver of a message, if they have not been seen before (see Chatbots as Middlemen article to understand why)
    • NotificationsScorable on the other hand will look for specific backchannel messages, where the Text property of the Activity will read "notification" and then extracts the actual notification content from another property of Activity named ChannelData
    • In this case no backchannel message is detected and the root dialog is invoked
  4. Root dialog handles the message as it is defined to

In the second scenario a backend (or other entity) sends a backchannel message to the bot according to the notifications protocol we've agreed on:

  1. A notification specific backchannel message is sent to the bot
  2. The received Activity instance is seemingly passed to the root dialog in MessagesController class - however it the dialog will never receive the Activity because of the NotificationsScorable class, and that is because...
  3. Autofac happens
    • Now a backchannel message is detected by NotificationScorable, the score will exist and its value will be 1.0d (fancy way of saying the value of action double type is exactly 1), and as a result, NotificationsManager will be told to handle the Activity instance and the root dialog is never invoked
  4. NotificationsManager uses MessageRouterManager to deliver the notifications to desired users

Why Autofac?

As you noticed from the descriptions of the previous scenarios, Autofac - an implementation of inversion of control (IoC) container - makes it harder to understand the execution flow of the code without a thorough inspection (or proper documentation). In other words, IoC makes it more difficult to have self-documenting code. That's why I don't like Autofac or IoC containers in general. I'd rather have the backchannel detection (and other things) written in MessagesController class, before the decision to forward the Activity instance to the root dialog is made:

WebApiConfig.MessageRouterManager.MakeSurePartiesAreTracked(activity);
string notificationData = string.Empty;

if (NotificationsManager.TryGetNotificationData(activity, out notificationData))
{
    // A notification related backchannel message was detected
    await NotificationsManager.SendNotificationAsync(notificationData);
}
else
{
    await Conversation.SendAsync(activity, () => new RootDialog());
}

However, if you are using the Microsoft Bot Builder SDK, there is no escape from Autofac since the SDK is built using it. You can still avoid the use in the code you write. But that's my preference. You will have yours and it's neither right nor wrong. Only debatable :)

See also