A common bot use case that is often discussed is how to have a bot contact a user based on some triggered event or lengthy job or an external event such as a state change in the system. These type of bots are often referred to as proactive bots.

In this post I am going to show you how to create a proactive bot using the Microsoft Bot Framework and Microsoft Azure. I have decided to write the solution using C# but all of the concepts are just as valid for Node.js as well.

The scenario we are going to cover is simple.

Ask a bot to notify me when an order is despatched

To follow the steps in this post you will need:

Here is an overview of the general architecture you will be building:

General Architecture

You can find all the code you need in my GitHub here.

1. Building and Registering the Bot.

The code to build the bot can be found here. To use this code you must:

  • First decide where to publish your bot. If you are using Visual Studio then an easy way to do so is to right-click the project and choose publish. From here you can choose to publish directly to Azure. If you require additional help deploying your app then I encourage you to look at this resource. Please make a note of the website url – you will need this in the next step.
  • Next, register your bot in the Microsoft Bot Framework. Full instructions on how to do this can be found here. Important: the messaging endpoint is the url noted above and include /api/messages, e.g. https://mybot.azurewebsites.net/api/messages. You should make a note of the Bot Handle, Microsoft App ID and the Microsoft App Password (auto generated) as  you will need these values for the next step.

Register Bot

  • Back in Visual Studio project update the web.config with the Bot Handle, Microsoft App ID and Microsoft App Password. 

Web Config

  • Next, configure an Azure Storage Account. This Storage Account will be used for both the Table Storage and Queues. If you don’t already have a Storage Account then follow these steps here to create a new account. Once created you will need the Storage Account connection string. To get this string from the Azure Portal find your Storage Account and under Settings—>Access Keys, copy the Connection Sting value and paste it as the value of the StorageConnectionString in the web.config.
  • Finally, rebuild the solution and re-publish. You can test the bot works either by adding your Bot to your favourite channel such as Skype, Slack, or Teams or by using the web chat pane – both options can be found in the My bots (choose your bot) menu option in the Microsoft Bot Framework portal.

2. Creating the Azure Functions

Azure functions allow you to develop and deploy small pieces of code in the language of your choice and in the cloud without setting up infrastructure. If you are new to Azure Functions then I would definitely recommend having a look at this tutorial. As well as being a great getting started it will also introduce you to working with Azure Queues which form the basis of our solution

As per the general architecture diagram above, will need to create 2 Azure Functions: one to capture the subscription posted from the Bot and another to capture the back office event being completed. So looking at each one in turn:

Subscription Trigger

This function is triggered when a new Queue Message is added to an Azure Queue. To create this function select the ‘+’ symbol under the Azure Function Plan and choose the QueueTrigger-CSharp template. Give, your function the name SubscriptionTrigger and then specify the Queue name as subscription-items and select from the dropdown the Storage Account you created previously.

Once the function has been created, you need to allow the function to update an Azure Table. To do this select the Integrate menu option under the Azure Function – select + New Input and choose Azure Table Storage. Change both the Table parameter name and Table name to subscriptionTable, and select from the dropdown the Storage Account you created previously.

Back in the body of the function (run.csx) copy the code found here. Note, the parameter names for the types SubscriptionMessage and CloudTable need to match what you entered as part of the Integrate step. Choose Save and I suspect you will get an error complaining about the type ConversationReference. This is a class specified in the Microsoft.Bot.Builder framework which is available as a Nuget package. We need to therefore include a reference to this framework and to do so we need to add a new file. The diagram below shows the new file (project.json) and the associated code:

Project Json

Once you have added the file, try saving the function again and hopefully the code should compile successfully.

At this stage, you should be able to test your code to see if the Subscription side of the solution is working successfully. To check, go to the bot channel (e.g. web chat, Skype, Slack, etc.) of your choice and type the message #1234 . You should get a response from the bot that the subscription to that order has been noted. If you look in your Azure Table Storage (try the tool Azure Storage Explorer) you should see a new row in the subscriptionTable.

Event Trigger

Like the previous function, this function is triggered when a new Queue Message is added to an Azure Queue. This time however, rather than the user triggering the new message from their bot, this message gets added as a result of a back office system when the order has been despatched.

Therefore, as per the Subscription Trigger, create a new function using the QueueTrigger-CSharp template. The Queue name should be set as event-items and the Storage Account should be the account you set up previously.

Once the function has been saved, again as per the Subscription Trigger, use the Integrate menu item to add a new Azure Table Storage input. As this function will be reading from the table created as part of the subscription trigger, you should use the same Table name, subscriptionTable.

This function also makes use of the Microsoft.Bot.Builder type ConversationReference so as per above add a new file called project.json and add a reference to Microsoft.Bot.Builder.

Now click on the file run.csx and copy the code from here.

Finally, one thing you will notice in the code is that it has a reference to a MicrosoftAppPassord, MicrosoftAppId. These are values that are required to be added to the Function’s app settings. To add them go to the Function App—>Platform Features—>Application settings.

App Setting Menu

Under App settings in the task pane that will open you should add the names MicrosoftAppId and MicrosoftAppPassword. The values for these 2 new keys should be values you captured when registering your bot. Note, they should match what you have in your Bot project’s web.config file.

3. Configuring the ‘Some Back-office App’

The final project that I have included in the solution is a simple console app, the DeleteMeClient (the DeleteMe reference is meant to refer the fact that it should thrown away and replaced with a concrete app Smile). 

This console app is meant to represent the back-office app that is responsible for triggering the bot to tell the user their order has now been despatched.

To use the app you will need to update it’s app.config with the correct Storage Account Connection String as per the setting specified in the Bot project’s web.config. You should also ensure the queue name in Program.cs matches the one specified in the Event Trigger’s integration. If you have followed my recommendation this should be event-items.

4. Pulling it altogether!

Now that we have our Bot published and our Azure Function services configured, let’s pull it altogether and play out the scenario. Note, to start any proactive scenario the user must interact with the bot first.

  • Using the Bot Channel of your choice, for illustration purposes I have configured Skype, type an order number in the format #XXXX, e.g. #1234
  • You should get a message response telling you your request has been noted.

image

  • Now run the DeleteMeClient console app and when prompted for an order number enter 1234
  • The bot will respond to you letting you know the order has despatched:

image

Try extending this simple scenario by subscribing to the same order but in a different channel, e.g Slack or Microsoft Teams. You should see that when the order is despatched you get a notification in both channels.

5. What if the user wants to act on the notification they have been sent?

Usually when we start a dialog / conversation with a bot we do so with the goal of achieving a desired outcome. To help a user reach that desired outcome the bot is usually designed with some aspect of workflow in mind. In this scenario that workflow is disrupted when the user is notified when the order is despatched. Simply notifying the user is not always enough…what if the user wants to act upon the notification and get access to further actions. In a world of prescribed workflows this is not often easy. What we need to solve is how to disrupt a prescribed dialog with a notification, let the user act upon that notification and then once they have finished let them continue with their original dialog.

We can solve this problem using Scorable Dialogs:

Scorable dialogs monitor all incoming messages to a bot and decide if they should try to handle a message. If a scorable matches against an incoming message then it can then handle the response to the user rather than it being picked up by the current dialog in the stack.

In our solution we have defined a Scorable (ScorableActions.cs) to handle when a user responds with the message ‘show actions’. In this context the Bot handles this request by creating a new dialog with the user asking them if they want to view the order or notify the customer of the order.

The result, the conversation is disrupted and the user is allowed to complete an action:

image

For more details on Scorable Dialogs, I would highly recommend you watch MVP James Mann’s video and read MVP Gary Pretty’s blog post.

6. What about the disruption to the conversation flow?

The flow above is very simple. In the real world an order won’t be despatched in 5 minutes and I suspect a bot’s applicability will be more than: tell me when an order is despatched.

My point is, the triggered event may occur after 5 minutes, 5 hours, 5 days, even 5 months or 5 years. Given this time frame, there is the potential that the user may already be in mid conversation with the bot when a notification is triggered. The complication then is how to respond back to user with the notification and offer them further actions without dramatically affecting the user’s current dialog and therefore experience.

Let’s consider the following conversation flow:

  • User asks the bot to notify them when order #5674 is despatched
  • The bot immediately responds telling the user their request has been noted.

image

  • The user then starts a dialog with the bot unrelated to orders being despatched:

image

  • In the middle of this conversation, the bot responds with the notification that order 5674 has been despatched. The user then decides they want to act upon the notification they have just received, thus disrupting the original conversation flow:

image

Once they view the order, how can we remind the user where they were in the original conversation flow? To do this we make use of the frame collection associated with the bot context. This collection is a list of the current dialogs that are in play. By interrogating this collection and implementing a custom-defined function we can determine the last message that was sent and then include it in the closing response of the Scorable dialog:

image

You can see the code in action by first looking at RootDialog.cs. This class implements a custom interface called ILastDialogMessageSentToUser.

The purpose of this interface is two-fold: keep a track of the last message sent; allow the Scorable implementation to filter the bot context collection based on its type:

RootDialog.cs

image

ScorableActionsDialog.cs

image

Note, you’ll notice in each of the bot responses I have included the name of the dialog responsible for the message. This is deliberate and hopefully illustrates how Scorable Dialogs can help you traverse between dialogs.

7. Summary

In this blog you have learnt how to use the Microsoft Bot Framework and Azure to create a proactive bot. You have also learnt techniques on how to handle disruptions that notifications cause when they interrupt conversational flows.

When using the Microsoft Bot Framework, to configure the bot to be available to a particular channel (e.g. Skype. Slack, Facebook, Teams, etc.) you need to host the Bot service on a public URL endpoint. The channel won’t be able to access your bot service if it is on a local server port hidden behind a NAT or firewall.

When designing / building / testing your code you don’t always want to have to keep redeploying and more importantly paying hosting costs – introducing ngrok,

ngrok allows you to create secure tunnels to localhost and thereby exposes your local server to the internet.

So what I thought I would do is walk you through:

  1. configuring a simple Node.js bot using the Bot Builder SDK samples and deploying the bot to your localhost server
  2. using ngrok to expose your bot to the public internet
  3. registering the bot on the Microsoft Bot Framework
  4. adding the bot to your Skype channel

 

1. Create a simple Hello, World! Bot

The easiest way to do this is to use one of the sample bots found here. Follow the instructions to clone the repository and then navigate to one of the samples. If you are getting started with bots then my advice is to start with one of the Hello World samples. For the purpose of this walkthrough I used the hello-ChatConnector.

If you want to make sure your bot is working without having to register it first, try using the Bot Framework Emulator following these steps:

  1. In a Node.js console navigate to the hello-ChatConnector found at \botbuilder\Node\examples\hello-ChatConnector
  2. Run the command node app.js
  3. Make a note of the port, if you have not changed any of the app.js code the port should be 3978
  4. Open the emulator and change the Bot Url to http://localhost:3978/api/messages
  5. Try the emulator by posting a message to the chat window. You should see something like this:

 

image

 

2. Using ngrok

Given the bot is being hosted on localhost:3978 now use ngrok to expose this port to the public internet. To do this simply type at a command prompt ngrok http 3978. You should the following UI:

image

Copy the forwarding Url – this is the public endpoint for the Bot service.

For the purpose of trying this out in the emulator, copy this Url to the Bot Url as per #1 – remember to include /api/messages.

You should notice that the emulator Url now shows as error ! to solve this open another command prompt and type ngrok http –host-header rewrite=9000

Doing so should now enable you to run the emulator but using public endpoints:

image

 

3. Register the bot on the Microsoft Bot Framework

If you haven’t already signed up to the Microsoft Bot Framework then you need to that first. Once signed up and signed in choose the Register a Bot tab.

The form will guide you through the steps required to register the bot. Ensure you copy the Microsoft App ID and Password somewhere safe, you will need to add these to your Bot service code. For the Messaging Endpoint use the forwarding Url captured in #2 that you used as the Bot Url.

4. Adding the bot to the Skype channel

Go back to the bot sample configured in step #1. You need to amend the app.js code file to include the Microsoft App ID and Password copied in step #3.

Once you have saved the changes follow the steps in #1 and #2 to deploy your bot to your local server and then use ngrok to make it public to the internet.

To ensure the changes you have made still work, use the emulator to test – you will need to update the Microsoft App ID and Microsoft App Password with the values captured in step #3. If you don’t you will get a 401 Unauthorized.

Finally, go back to the Microsoft Bot Framework portal and add your bot to the Skype Channel.

 

image

 

And that is it…you have your first bot running locally being served to the public internet using ngrok and available to chat with using the Skype channel.

As a next step, you can debug your bot service within Visual Code using the steps described in here