Microsoft Bot Framework: Getting Started – Understanding Dialogs and Maintaining states between conversations
When end user interacts with Bot a set of conversations is exchanged. This flow of conversation has to be managed. Dialog comes to the rescue here and handles the conversation flow. During these conversations lot of information and data are shared. Bot should be intelligent enough to handle conversation state so that it can retain and use required information across conversations. In this article we will explore the concept of Dialog and how to maintain state in the conversation flows.
Prerequisites
Before deep diving into this article I would strongly recommend you to go through all the previous articles of this series. Here in this article we will not be focusing on the basic concepts of Bot Framework.
Microsoft Bot Framework : Getting Started - Building the first Hello Bot
Microsoft Bot Framework: Getting Started – Making the Bot Intelligent using Text Analytics Sentiment API from Microsoft Cognitive Services
We will concentrate here on Dialogs and State management for the Bot.
Understanding Dialog
Dialog helps in managing flow of conversations between the end user and the Bot. This represents a single session consisting of set of conversations between the end user and the Bot. This starts when the user sends the first message to the Bot incorporating Dialog and ends when it responds back to the last message of the user. Below is an example of a Dialog between end user and the Bot.
http://i.imgur.com/4X4LDE5.jpg
Microsoft Bot Framework provides an interface IDialog. Dialog class needs to implement IDialog interface and implement its method StartAsync to build a Dialog. Dialog can be chained. We will try chaining of Dialogs in the future articles of this series.
Maintaining States between conversations
When the user starts a dialog with the Bot and interacts, series of text messages and information are exchanged. Bot needs to capture the information and maintain the data across conversations in the Dialog. This can be done using UserData class of dialog context. Below are few useful methods of UserData that can be used to manage states during conversations.
SetValue – This is used to set data to the dialog context against a key.
GetValue – This is used to get data from the dialog context for a key.
TryGetValue is a safer alternative to this.
Using Dialog and State Management
Now that we have an idea of Dialog and UserState, let us build a Bot that uses Dialog. Below listed are steps to build this.
Step 1
Open Visual Studio and create a project of type Bot Application.
Step 2
Go to Dialogs folder in the solution and add below InsuranceDialog class.
using System;
using System.Threading.Tasks;
using Microsoft.Bot.Builder.Dialogs;
using Microsoft.Bot.Connector;
namespace HelloDialogBot.Dialogs
{
[Serializable]
public class InsuranceDialog : IDialog<object>
{
public async Task StartAsync(IDialogContext context)
{
//Set this flag as true when the user initiates communication with the Bot for the first time. We will maintain the data in the context
//Bot will not action anything further if this flag is true except sending the welcome message.
context.UserData.SetValue<bool>("isFirstTextFromUser", true);
//Send welcome message to user. Ask for user name
await context.PostAsync(@"Welcome to ""Quick Insurance - World's best Insurance Provider"". May I know your name please. ");
context.Wait(MessageReceivedAsync);
}
private async Task MessageReceivedAsync(IDialogContext context, IAwaitable<object> result)
{
string insurerName = string.Empty;
string insuranceID = string.Empty;
string complaint = string.Empty;
bool isFirstTextFromUser = false;
//Gets value of flag isFirstTextFromUser from the context
context.UserData.TryGetValue<bool>("isFirstTextFromUser", out isFirstTextFromUser);
//Gets value of flag insurerName from the context
context.UserData.TryGetValue<string>("insurerName", out insurerName);
//Gets value of flag insuranceID from the context
context.UserData.TryGetValue<string>("insuranceID", out insuranceID);
//Gets value of flag complaint from the context
context.UserData.TryGetValue<string>("complaint", out complaint);
var activity = await result as Activity;
//Do not get into this loop if this is the first message from the user. This will avoid setting user's first message
//to insurerName
if (!isFirstTextFromUser)
{
//insuranceName is blank corresponds that user is reponding to the Bot's reply -
//Welcome to "Quick Insurance - World's best Insurance Provider". May I know your name please.
//Capture insurerName
if (string.IsNullOrWhiteSpace(insurerName))
{
//Set insurerName to context
context.UserData.SetValue<string>("insurerName", activity.Text);
//Prompt user to provide identification number
await context.PostAsync("Please provide your insurance identification number");
}
//insuranceID is blank and insurerName is not blank corresponds that user is reponding to the Bot's reply -
//Please provide your insurance identification number
//Capture insuranceID
else if (string.IsNullOrWhiteSpace(insuranceID))
{
//Set insuranceID to the context
context.UserData.SetValue<string>("insuranceID", activity.Text);
//Prompt user to provide complaint
await context.PostAsync("Let me know your complaint");
}
//insuranceID is not blank and insurerName is not blank corresponds that user is reponding to the Bot's reply -
//Let me know your complaint
//Capture complaint text
else if (string.IsNullOrWhiteSpace(complaint))
{
//Set complaint to the context
context.UserData.SetValue<string>("complaint", activity.Text);
//Wrap up
await context.PostAsync("Thank you. We have registered your complaint as Name : " + context.UserData.GetValue<string>("insurerName")
+ ", Insurance ID : " + context.UserData.GetValue<string>("insuranceID")
+ ", Complaint : " + activity.Text + ". Our representative will get back to you shortly. Please end the conversion chat");
}
}
else
{
context.UserData.SetValue<bool>("isFirstTextFromUser", false);
}
context.Wait(MessageReceivedAsync);
}
}
}
Step 3
Go to Controlers\MessagesController.cs and replace Post method with below.
public async Task<HttpResponseMessage> Post([FromBody]Activity activity)
{
if (activity.Type == ActivityTypes.Message)
{
//Do converstation with user using InsuranceDialog
await Conversation.SendAsync(activity, () => new Dialogs.InsuranceDialog());
}
else
{
HandleSystemMessage(activity);
}
var response = Request.CreateResponse(HttpStatusCode.OK);
return response;
}
Step 4
Build the solution and run. The service starts up.
http://i.imgur.com/uLJRbaU.jpg
Step 5
Open Bot framework emulator and communicate with Bot. Below is a sample communication with the Bot we built.
http://i.imgur.com/BZKK3NL.jpg
Source Code
This solution is built using Visual Studio 2017 Community Edition. You can get the source from GitHub repository here.
Next Steps
Below listed are articles that you can check out as next steps.
Microsoft Bot Framework: Getting Started – Sending a File to the Bot
Microsoft Bot Framework: Getting Started – Bot sends an attachment file to the end user