Skip to content

Files

Latest commit

5415d64 · Sep 22, 2016

History

History
This branch is 3842 commits behind microsoft/BotBuilder-Samples:main.

core-State

Folders and files

NameName
Last commit message
Last commit date

parent directory

..
Sep 22, 2016
Sep 22, 2016
Sep 22, 2016
Sep 22, 2016
Sep 22, 2016
Sep 22, 2016
Sep 22, 2016
Sep 22, 2016
Sep 22, 2016
Sep 22, 2016
Sep 22, 2016
Sep 22, 2016
Sep 22, 2016
Sep 22, 2016
Sep 22, 2016
Sep 22, 2016
Sep 22, 2016

State API Bot Sample

A stateless sample bot tracking context of a conversation.

[![Deploy to Azure][Deploy Button]][Deploy CSharp/State] [Deploy Button]: https://azuredeploy.net/deploybutton.png [Deploy CSharp/State]: https://azuredeploy.net

Prerequisites

The minimum prerequisites to run this sample are:

  • The latest update of Visual Studio 2015. You can download the community version here for free.
  • The Bot Framework Emulator. To install the Bot Framework Emulator, download it from here. Please refer to this documentation article to know more about the Bot Framework Emulator.

Code Highlights

The Bot Framework provides several ways of persisting data relative to a user or conversation. Behind the scenes the Bot Framework uses the Bot State Service for tracking context of a conversation. This allows the creation of stateless Bot web services so that they can be scaled.

The IDialogContext has several properties which are useful for tracking state.

Property Use cases
ConversationData Remembering context data associated with a conversation.
PrivateConversationData Remembering context data associated with a user in a conversation.
UserData Remembering context data associated with a user (across all channels and conversations).

Check out the use of context.ConversationData in the StartAsync method to store a default search city. ConversationData is shared for all users within a conversation.

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

    if (!context.ConversationData.TryGetValue(ContextConstants.CityKey, out defaultCity))
    {
        defaultCity = "Seattle";
        context.ConversationData.SetValue(ContextConstants.CityKey, defaultCity);
    }

    await context.PostAsync($"Welcome to the Search City bot. I'm currently configured to search for things in {defaultCity}");
    context.Wait(this.MessageReceivedAsync);
}

Also, check out the use of context.PrivateConversationData in the MessageReceivedAsync method where logic is included to override data stored in the ConversationData property. PrivateConversationData is private to a specific user within a conversation.

    string userCity;

    var city = context.ConversationData.Get<string>(ContextConstants.CityKey);

    if (context.PrivateConversationData.TryGetValue(ContextConstants.CityKey, out userCity))
    {
        await context.PostAsync($"{userName}, you have overridden the city. Your searches are for things in  {userCity}. The default conversation city is {city}.");
    }
    else
    {
        await context.PostAsync($"Hey {userName}, I'm currently configured to search for things in {city}.");
    }

In contrast, check out the use of context.UserData in the ResumeAfterPrompt method to remember the user's name. UserData is shared across all channels and conversations for this user.

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

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

        context.UserData.SetValue(ContextConstants.UserNameKey, userName);
    }
    catch (TooManyAttemptsException)
    {
    }

    context.Wait(this.MessageReceivedAsync);
}

Additionally, Dialog State is automatically persisted with each message to ensure it is properly maintained between each turn of the conversation and it follows the same privacy rules as PrivateConversationData. Sub-dialogs have their own private state and does not need to worry about interfering with the parent dialog. Check out the use of the userWelcomed variable in the StateDialog class to keep track if the welcome message was already sent to the user.

if (!this.userWelcomed)
{
    this.userWelcomed = true;
    await context.PostAsync($"Welcome back {userName}! Remember the rules: {HelpMessage}");

    context.Wait(this.MessageReceivedAsync);
    return;
}

Outcome

The first time you run this sample it will display a welcome message and configure itself to issue search queries for the 'Seattle' city, storing this value in the ConversationData bag. It will also prompt you for your name and store it in the UserData bag and display a help message. Issuing the change my city command will allow you to change the search city for this conversation only and just for your user, storing the value in the PrivateConversationData bag.

Sample Outcome

Subsequently, you can start a new conversation (In the Bot Framework Channel Emulator this can be done by using the 'ConversationNames - New' button) and this time the bot will remember you name but will forget the city override we executed in the previous conversation. Using the change city command this can be changed for all the users in the conversation.

Sample Outcome

When a another user arrives to the conversation (In the Bot Framework Emulator this is done by editing the 'User' field) the bot will remember its name (Or prompt for the user name depending on any previous conversation) and maintain the previous search city set.

Sample Outcome

To get more information about how to get started in Bot Builder for .NET and Conversations please review the following resources: