Bot Framework State is a service to track the context of a previous conversation with a specific user.  Bot Builder SDK users are well-aware of the importance of this feature as it helps you in data analysis and data auditing. Sentiment analysis and funnel analysis are the scenarios where you need Bot conversation and machine learning models to track the quality of the data where natural language fails to handle input messages. It also involves the number of active or new users that determines the participation and engagement level of the users called Metrics. The need of Bot conversation is also felt when the data needs auditing or one has to store data for auditing purposes.

How to Conversation Data?

JSON format structure offers three different ways to store data and this process is known as property bags.

UserData: User data is termed as user property bag and its ID is called the user ID. The data which isn’t dependent on any conversation and needs to be stored globally falls in this category. It lets you track the personal information of a user like username, DOB, and designation.

{

“id”: “emulator:userdefault-user”,

“botId”: “<your Bot ID>”,

“channelId”: “emulator”,

“conversationId”: “<your conversation ID>”,

“userId”: “<user ID>”,

“data”: {

“username”: “Fernando de Oliveira”

},

“_rid”: “9G5GANrnJQADAAAAAAAAAA==”,

“_self”: “dbs/9G5GAA==/colls/9G5GANrnJQA=/docs/9G5GANrnJQADAAAAAAAAAA==/”,

“_etag”: “\”01008737-0000-0000-0000-5993a11d0000\””,

“_attachments”: “attachments/”,

“_ts”: 1502847257

}

If you are using C# then opt for the following code:

private bool userWelcomed;

public virtual async Task MessageReceivedAsync(IDialogContext context, IAwaitable<IMessageActivity> result)
{
var message = await result;

string userName;

if (!context.UserData.TryGetValue(“username”, out userName))
{
PromptDialog.Text(context, ResumeAfterPrompt, “Before get started, please tell me your name?”);
return;
}

if (!userWelcomed)
{
userWelcomed = true;
await context.PostAsync($”Welcome back {userName}!”);

context.Wait(MessageReceivedAsync);
}
}

private async Task ResumeAfterPrompt(IDialogContext context, IAwaitable<string> result)
{
try
{
var userName = await result;
userWelcomed = true;

await context.PostAsync($”Welcome {userName}!”);

context.UserData.SetValue(“username”, userName);
}
catch (TooManyAttemptsException ex)
{
await context.PostAsync($”Oops! Something went wrong 🙁 Technical Details: {ex}”);
}

context.Wait(MessageReceivedAsync);
}

 

ConversationData: This property bag is called conversation property bag and associated to a group conversation. The associated ID of this property bag is the conversation ID and the data stored in this bag is visible to every group member. It requires a specific language for the bot in order to interact with all group members.

{
“id”: “emulator:conversation<your conversation ID>”,
“botId”: “<your Bot ID>”,
“channelId”: “emulator”,
“conversationId”: “<your conversation ID>”,
“userId”: “default-user”,
“data”: {
“defaultLanguage”: “pt-BR”
},
“_rid”: “9G5GANrnJQAEAAAAAAAAAA==”,
“_self”: “dbs/9G5GAA==/colls/9G5GANrnJQA=/docs/9G5GANrnJQAEAAAAAAAAAA==/”,
“_etag”: “\”0800357b-0000-0000-0000-598b52060000\””,
“_attachments”: “attachments/”,
“_ts”: 1502302725
}

See the example to save data in the Conversation bag.

public async Task StartAsync(IDialogContext context)
{
string language;

if (!context.ConversationData.TryGetValue(“defaultLanguage”, out language))
{
language = “pt-BR”;
context.ConversationData.SetValue(“defaultLanguage”, country);
}

await context.PostAsync($”Hi! I’m currently configured for {language} language.”);

context.Wait(MessageReceivedAsync);
}

 

PrivateConversationData: Private Conversation data is the combination of user ID and conversation ID and the stored data is visible only to the latest user. The property bag is designed to store temporary data only which you can remove later. The example is the mentioned below.

{
“id”: “emulator:private<your conversation ID>:default-user”,
“botId”: “<your Bot ID>”,
“channelId”: “emulator”,
“conversationId”: “<your conversation ID>”,
“userId”: “default-user”,
“data”: {
“ResumptionContext”: {
“locale”: pt-BR”,
“isTrustedServiceUrl”: false
},
“DialogState”: “<dialog state ID>”,
“orderId”: “<order ID>”
},
“_rid”: “9G5GANrnJQAXAAAAAAAAAA==”,
“_self”: “dbs/9G5GAA==/colls/9G5GANrnJQA=/docs/9G5GANrnJQAXAAAAAAAAAA==/”,
“_etag”: “\”0100f938-0000-0000-0000-5993ab090000\””,
“_attachments”: “attachments/”,
“_ts”: 1502849796
}

Follow the example to store data in PrivateConversationData:

string orderId;

if (!context.PrivateConversationData.TryGetValue(“orderId”, out orderId))
{
// Generic method to generate an order ID
orderId = await GetOrderIdAsync();

context.PrivateConversationData.SetValue(“orderId”, orderId);

await context.PostAsync($”{userName}, this is your order ID: {orderId}”);
}

 

How to Use Cosmos DB Instead of Bot Framework State?

Bot Framework is designed for prototyping and it uses the Bot Framework State to store the conversation data. The 32KB storage size limit can be used for development and testing environment. NoSQL DB allows the user to store data in the form of the documents which is called Azure Cosmos DB and the multi-model database has important properties like global distribution, horizontal scalability, and availability.

How to Store Conversation Data?

Bot Builder SDK Azure Extensions is used to customize the bot data conversation and you have to edit Global.asax file if you are using C# to develop your bot with Bot Builder SDK.

protected void Application_Start()

{

// Adding DocumentDB endpoint and primary key

var docDbServiceEndpoint = new Uri(“<your documentDB endpoint>”);

var docDbKey = “<your documentDB key>”;

// Creating a data store based on DocumentDB

var store = new DocumentDbBotDataStore(docDbServiceEndpoint, docDbKey);

// Adding Azure dependencies to your bot (documentDB data store and Azure module)

var builder = new ContainerBuilder();

builder.RegisterModule(new AzureModule(Assembly.GetExecutingAssembly()));

// Key_DataStore is the key for data store register with the container

builder.Register(c => store)

.Keyed<IBotDataStore<BotData>>(AzureModule.Key_DataStore)

.AsSelf()

.SingleInstance();

// After adding new dependencies, update the container

builder.Update(Conversation.Container);

GlobalConfiguration.Configure(WebApiConfig.Register);

}

Click on the Data Explorer to check the stored documents in Cosmos DB.