Managing state and logging chat history in Microsoft bot framework

Somak Das
Chatbots Life
Published in
8 min readDec 30, 2017

--

In our earlier posts on Microsoft bot framework we have see basic formflow feature of bot framework and some of the advanced stuffs as well. In this blog we are going to discuss about what all are the ways in which we can manage conversation states in bot framework and how we can maintain conversation history, i.e how we can maintain a log of all the conversations that are taking place between the bot and its users.

Before we proceed on how to do that lets talk about scenarios why they are necessary and what all are the use case that it can serve. Lets proceed one by one and start with state management first.

Manage state data:

The Bot Framework State service enables your bot to store and retrieve state data that is associated with a user, a conversation, or a specific user within the context of a specific conversation. State data can be used for many purposes, such as determining where the prior conversation left off or simply greeting a returning user by name. If you store a user’s preferences, you can use that information to customize the conversation the next time you chat. For example, you might alert the user to a news article about a topic that interests her, or alert a user when an appointment becomes available.

If your bot uses dialogs, conversation state (the dialog stack and the state of each dialog in the stack) is automatically stored using the Bot Framework State service.

To know more about state service that botframewrok provides by default and the different methods available to store the states please see the official documentation here.

The state service in botframework by default uses state.botframework.com to store the state. Since its a shared service it is limited to scaling and throughput and size.

Microsoft provides us In-Memory Data Storage for testing purpose. You can use that in for development but its not recommended to use that in production since its volatile and temporary and has a limitation of 32 kb. For a list of available methods for managing states, please follow the official link here.

Manage custom data storage:

Microsoft provides us the flexibility to implement our own data storage to store the bot’s state data to some external storage or choose from the azure extension that is already provided by the Microsoft. Now let us look at the two azure extensions that are already provided my Microsoft and we will also see how to configure them quickly in our bot.

  1. Manage state data with Cosmos DB
  2. Manage state data with Table storage

Manage state data with Cosmos DB :

Azure Cosmos DB is one of the azure extension options that Microsoft provides to manage state data in production environment.

What is Cosmos DB?

Azure Cosmos DB is Microsoft’s globally distributed, multi-model database. With the click of a button, Azure Cosmos DB enables you to elastically and independently scale throughput and storage across any number of Azure’s geographic regions. It offers throughput, latency, availability, and consistency guarantees with comprehensive service level agreements.

If you are new to Cosmos DB please go through their official document here.

Some of the advantages that Cosmos DB provides are:

  • Higher state API throughput (more control over performance)
  • Lower-latency for geo-distribution
  • Control over where the data is stored
  • Access to the actual state data
  • Store more than 32 kb of data

In order to enable our bot to use Cosmos DB for managing its state we need to set up a Cosmos DB database first.

Prerequisites: Assuming that a botframework setup has already been done, here are the prerequisites to use Cosmos DB.

  • Microsoft Azure Account
  • Bot Builder Azure NuGet Package
  • Autofac Web Api2 NuGet Package

Set up the Azure Cosmos DB database

  1. After you’ve logged into the Azure portal, create a new Azure Cosmos DB database by clicking New.
  2. Search Azure Cosmos DB and click Create.
  3. Fill in the fields. For the API field, select SQL (DocumentDB). When done filling in all the fields, click the Createbutton at the bottom of the screen to deploy the new database.
Fig 1

4. After the new database is deployed, navigate to your new database. Click Access keys to find keys and connection strings. Your bot will use this information to call the storage service to save state data.

Fig 2

Install NuGet packages

  • Microsoft.Bot.Builder.Azure
  • Autofac.WebApi2

Add connection string

We need to add the following entries into the Web.config file:

<add key="DocumentDbUrl" value="Your DocumentDB URI"/>
<add key="DocumentDbKey" value="Your DocumentDB Key"/>

We need to replace the value with the URI and Primary Key found in our Azure Cosmos DB as marked in Fig 2 and save the Web.config file.

Modify your bot code

To use Azure Cosmos DB storage, add the following lines of code to your bot’s Global.asax.cs file.

using System;
using Autofac;
using System.Web.Http;
using System.Configuration;
using Microsoft.Bot.Connector;
using Microsoft.Bot.Builder.Azure;
using Microsoft.Bot.Builder.Dialogs;
using Microsoft.Bot.Builder.Dialogs.Internals;
var uri = new Uri(ConfigurationManager.AppSettings["DocumentDbUrl"]);
var key = ConfigurationManager.AppSettings["DocumentDbKey"];
var store = new DocumentDbBotDataStore(uri, key);
Conversation.UpdateContainer(
builder =>
{
builder.Register(c => store)
.Keyed<IBotDataStore<BotData>>(AzureModule.Key_DataStore)
.AsSelf()
.SingleInstance();
builder.Register(c => new CachingBotDataStore(store, CachingBotDataStoreConsistencyPolicy.ETagBasedConsistency))
.As<IBotDataStore<BotData>>()
.AsSelf()
.InstancePerLifetimeScope();
});

To test the setup run the bot in local emulator and check the state data from the Azure portal. Navigate to the Azure Cosmos DB database and click on the Data explorer to view the state data.

Fig 3
For more details on how data is stored and data structure please visit here.

Manage custom state data with Azure Table Storage

Another implementation that Microsoft has provided in the azure extension is the Azure Table storage. So this one has the same kind of functionality as the Azure Cosmos DB option only this one dumps everything to Azure storage instead of Cosmos DB. If you are new to Azure Storage you can learn more about it here.

Set up the Azure Table storage service

  1. After you’ve logged into the Azure portal, create a new Azure Table storage service by clicking on New.
  2. Search for Storage account that implements the Azure Table.
  3. Fill in the fields, click the Create button at the bottom of the screen to deploy the new storage service. After the new storage service is deployed, it will display features and options available to you.
Fig 4

4. Select the Access keys tab on the left, and copy the connection string for later use. Your bot will use this connection string to call the storage service to save state data.

Fig 5

Install NuGet packages

  • Microsoft.Bot.Builder.Azure
  • Autofac.WebApi2

Add connection string

Add the following entry in your Web.config file:

<connectionStrings>
<add name="StorageConnectionString"
connectionString="YourConnectionString"/>
</connectionStrings>

Replace “YourConnectionString” with the connection string to the Azure Table storage you saved earlier. Save the Web.config file.

Modify your bot code

In the Global.asax.cs file, add the following using statements:

using Autofac;
using System.Configuration;
using Microsoft.Bot.Connector;
using Microsoft.Bot.Builder.Azure;
using Microsoft.Bot.Builder.Dialogs;
using Microsoft.Bot.Builder.Dialogs.Internals;

Create an instance of the TableBotDataStore class The TableBotDataStore class implements the IBotDataStore<BotData>interface. The IBotDataStore interface allows you to override the default Connector State Service connection.

var store = new TableBotDataStore(ConfigurationManager.ConnectionStrings["StorageConnectionString"].ConnectionString);

Register the service as shown below:

Conversation.UpdateContainer(
builder =>
{
builder.Register(c => store)
.Keyed<IBotDataStore<BotData>>(AzureModule.Key_DataStore)
.AsSelf()
.SingleInstance();
builder.Register(c => new CachingBotDataStore(store,
CachingBotDataStoreConsistencyPolicy
.ETagBasedConsistency))
.As<IBotDataStore<BotData>>()
.AsSelf()
.InstancePerLifetimeScope();
});

Save the global.asax.cs file.

To test this setup you can run the bot application in local emulator and then view the state data in Azure storage explorer.

Logging conversation History:

So now that we have a clear idea about how we can store our bot state data, we are going to see what all ways or hooking points are there in the framework to Log conversation history in some external storage.

Note: Storing state and storing conversation data are two different things. The Bot Framework does not automatically save conversation details, as doing so could potentially capture private information that bots and users do not wish to share with outside parties. If your bot saves conversation details, it should communicate that to the user and describe what will be done with the data.

Why this is required?

  • For Analytics: Where the chat history may be required to feed that to some machine learning algorithm.
  • For book keeping purpose of course.
  • To improve the response of the LUIS Api if its in use and so on.

Intercept messages:

The middleware functionality in the Bot Builder SDK enables your bot to intercept all messages that are exchanged between user and bot. For each message that is intercepted, you may choose to do things such as save the message to a data store that you specify, which creates a conversation log, or inspect the message in some way and take whatever action your code specifies.

The Microsoft.Bot.Builder.History namespace provides interfaces and classes for doing this. In particular, the IActivityLogger interface contains the definition of the functionality that a class needs to implement to log message activities.

For an example implementation you can check out the DebugActivityLogger implementation of the IActivityLogger interface that writes message activities to the trace listeners only when running in debug.

For this demo we are going to use the TableLogger which is another implementation of IActivityLogger proied by Microsoft and is present in the same Azure extension.

Prerequisites:

  • An Azure storage acount
  • Bot Builder Azure NuGet Package

In the Global.asax.cs file add the following lines of code. Every message that is exchanged between user and bot (in either direction) will now trigger the LogAsync method in the DebugActivityLogger class.

public class WebApiApplication : System.Web.HttpApplication
{
protected void Application_Start()
{
var builder = new ContainerBuilder();
var tableName = ConfigurationManager.AppSettings["TableName"].ToString();var account = CloudStorageAccount.Parse(ConfigurationManager.AppSettings["TableStorage"]);//Used only for demo purpose. As the line suggests this deletes the table each time the application starts.account.CreateCloudTableClient().GetTableReference(tableName).DeleteIfExists();builder.RegisterModule(new TableLoggerModule(account, tableName));// After adding new dependencies, update the containerbuilder.Update(Conversation.Container);GlobalConfiguration.Configure(WebApiConfig.Register);
}
}

If you see the implementation of TableLogger you will find that it already implements the IActivityLogger interface and implements the LogAsync method which does all the action for us. So you can either use this logger implementation or can have some custom implementation of your own depending on your requirement and your storage option.

Hope this article will be useful for those who are starting to use botframework to create production level bots. In the next article we will discuss about few channel specific feature of chatbots. Till then Happy coding :)

--

--