Introduction To FormFlow With The Microsoft Bot Framework

Jul 24

Written by:
7/24/2016 5:03 PM  RssIcon

image

Using FormFlow with the Microsoft Bot Framework, allows you to quickly create a guided conversation, to gather information from a user, with the least amount of code. While it is less flexible than using Dialogs, it can be combined with Dialogs to increase its functionality.

 

A Walk-Thru

image

When a user begins a conversation with the Bot, it introduces itself, and asks the user’s name.

image

The Bot proceeds to ask questions and gather the responses.

image

A feature of FormFlow is that the user can type help at any time to obtain assistance with any question or the FormFlow itself.

As a developer, you get this functionality without the need to write any additional code.

image

The FormFlow continues until the form is complete.

Creating The Project

image

Download the Visual Studio 2015 Microsoft Bot Framework template (using this link)

Save the .zip file in the templates directory (located at: %USERPROFILE%\Documents\Visual Studio 2015\Templates\ProjectTemplates\Visual C# ).

This creates a template that you can use in Visual Studio to create Bot projects.

image

Open Visual Studio.

image

Create a new Project.

image

Select the Bot Application template and name the project HelloFormFlowBot.

image

The project will be created.

image

Right-click on the project, and select Add then New Item.

We will now create the class that will contain the logic for our FormFlow.

image

Add a new C# class called ProfileForm.cs.

Replace all the code with the following code:

 

using System;
using Microsoft.Bot.Builder.Dialogs;
using Microsoft.Bot.Builder.FormFlow;
namespace HelloFormFlowBot
{
    [Serializable]
    public class ProfileForm
    {
        // these are the fields that will hold the data
        // we will gather with the form
        [Prompt("What is your first name? {||}")]
        public string FirstName;
        [Prompt("What is your last name? {||}")]
        public string LastName;
        [Prompt("What is your gender? {||}")]
        public Gender Gender;
        // This method 'builds' the form 
        // This method will be called by code we will place
        // in the MakeRootDialog method of the MessagesControlller.cs file
        public static IForm<ProfileForm> BuildForm()
        {
            return new FormBuilder<ProfileForm>()
                    .Message("Welcome to the profile bot!")
                    .OnCompletion(async (context, profileForm) =>
                    {
                        // Tell the user that the form is complete
                        await context.PostAsync("Your profile is complete.");
                    })
                    .Build();
        }
    }
    // This enum provides the possible values for the 
    // Gender property in the ProfileForm class
    // Notice we start the options at 1 
    [Serializable]
    public enum Gender
    {
        Male = 1, Female = 2
    };
}

 

This code indicates the fields we will gather with our FormFlow.

Notice that the class, as well as the Gender enum that it consumes, is marked [Serializable].

The Microsoft Bot Framework requires that the classes must be serializable so the Bot can be stateless.

Save the file.

image

Open the MessagesController.cs file.

Add the following using statements at the top of the file (to support the FormFlow code):

 

using Microsoft.Bot.Builder.Dialogs;
using Microsoft.Bot.Builder.FormFlow;

 

Add the following MakeRootDialog method to the MessagesController class (to call the BuildForm method in the ProfileForm class we created earlier):

 

    internal static IDialog<ProfileForm> MakeRootDialog()
    {
        return Chain.From(() => FormDialog.FromForm(ProfileForm.BuildForm));
    }

 

Finally, alter the Post method in the MessagesController class to the following:

 

    public async Task<HttpResponseMessage> Post([FromBody]Activity activity)
    {
        // Detect if this is a Message activity
        if (activity.Type == ActivityTypes.Message)
        {
            // Call our FormFlow by calling MakeRootDialog
            await Conversation.SendAsync(activity, MakeRootDialog);
        }
        else
        {
            // This was not a Message activity
            HandleSystemMessage(activity);
        }
        // Return response
        var response = Request.CreateResponse(HttpStatusCode.OK);
        return response;            
    }

Save the file.

Test The Application

image

Hit F5 to run the application.

image

The web browser will open.

Note the port number and the web address.

image

Download, install, and run the Bot Framework Emulator (Windows) (also see: Mac and Linux support using command line emulator if you don’t have Windows).

When the emulator starts, connect to the Bot by setting the address to the the one indicted in the web browser (however, add /api/messages to the end).

image

Ensure that the Bot Url is connecting to the correct address.

image

Type a message, and click the send key (or press Enter).

image

You can now converse with the Bot and fill out the FormFlow.

Saving The Data

Currently the application does not save the responses from the user. In fact, after you fill the FormFlow out, it will simply ask you to fill it out again.

We can use the Bot State Service to save and retrieve the values.

Alter the BuildForm method in the ProfileForm.cs file to the following (to save the values entered into the form):

 

    public static IForm<ProfileForm> BuildForm()
    {
        return new FormBuilder<ProfileForm>()
                .Message("Welcome to the profile bot!")
                .OnCompletion(async (context, profileForm) =>
                {
                    // Set BotUserData
                    context.PrivateConversationData.SetValue<bool>(
                        "ProfileComplete", true);
                    context.PrivateConversationData.SetValue<string>(
                        "FirstName", profileForm.FirstName);
                    context.PrivateConversationData.SetValue<string>(
                        "LastName", profileForm.LastName);
                    context.PrivateConversationData.SetValue<string>(
                        "Gender", profileForm.Gender.ToString());
                    // Tell the user that the form is complete
                    await context.PostAsync("Your profile is complete.");
                })
                .Build();
    }

 

We are not only storing the values provided by the user, but we are also setting a flag (ProfileComplete), so that we don’t ask the user to fill out the form again.

Finally, alter the Post method in the MessagesController class to the following:

 

    public async Task<HttpResponseMessage> Post([FromBody]Activity activity)
    {
        // Detect if this is a Message activity
        if (activity.Type == ActivityTypes.Message)
        {
            // Get any saved values
            StateClient sc = activity.GetStateClient();
            BotData userData = sc.BotState.GetPrivateConversationData(
                activity.ChannelId, activity.Conversation.Id, activity.From.Id);
            var boolProfileComplete = userData.GetProperty<bool>("ProfileComplete");
            if (!boolProfileComplete)
            {
                // Call our FormFlow by calling MakeRootDialog
                await Conversation.SendAsync(activity, MakeRootDialog);
            }
            else
            {
                // Get the saved profile values
                var FirstName = userData.GetProperty<string>("FirstName");
                var LastName = userData.GetProperty<string>("LastName");
                var Gender = userData.GetProperty<string>("Gender");
                // Tell the user their profile is complete
                System.Text.StringBuilder sb = new System.Text.StringBuilder();
                sb.Append("Your profile is complete.\n\n");
                sb.Append(String.Format("FirstName = {0}\n\n", FirstName));
                sb.Append(String.Format("LastName = {0}\n\n", LastName));
                sb.Append(String.Format("Gender = {0}", Gender));
                // Create final reply
                ConnectorClient connector = new ConnectorClient(new Uri(activity.ServiceUrl));
                Activity replyMessage = activity.CreateReply(sb.ToString());
                await connector.Conversations.ReplyToActivityAsync(replyMessage);
            }
        }
        else
        {
            // This was not a Message activity
            HandleSystemMessage(activity);
        }
        // Send response
        var response = Request.CreateResponse(HttpStatusCode.OK);
        return response;
    }

 

image

 

Now the application will only ask the user to fill in the form one time, and display the values received using the Bot State Service.

The values will be persisted by the Microsoft Bot Framework keyed to that user in that conversation.

In our example we used PrivateConversationData, but the Bot State Service exposes the following methods, each with a different scope:

Method

Scoped

Description

SetUserData()

User

Remembering context object with a user

SetConversationData()

Conversation

Remembering context object with a conversation

SetPrivateConversationData()

User & Conversation

Remembering context object with a person in a conversation

 

Ai Help Website Links

Creating a Hello World! Bot Using The Microsoft Bot Framework

Introduction To Using Dialogs With The Microsoft Bot Framework

Creating A Facebook Bot Using Microsoft Bot Framework

Microsoft Links

Microsoft Bot Framework

FormFlow

Bot State Service

Bot Builder (GitHub)

Bot Framework Forum (stack overflow)

Visual Studio 2015 Bot Project Template

Bot Framework Emulator (Windows)

Download

You can download the code from the Download page

12 comment(s) so far...


Gravatar

Re: Introduction To FormFlow With The Microsoft Bot Framework


Hello friend, first of all congratulations for the material available on your site, fantastic. I would like to take a question, how do I return the data from the ProfileForm.cs class to the MessagesController.cs class or vice versa? I need to write to the database the user data (activity.ChannelId, activity.From.Id, etc) this, I managed to read your article, but also need to store the information that the user typed in the ProfileForm. I'm not sure how to return the ProfileForm data to the MessagesController class. Can you give me a hand? Thank you very much!

By André on   12/14/2016 3:57 AM
Gravatar

Re: Introduction To FormFlow With The Microsoft Bot Framework

@André - See: aihelpwebsite.com/Blog/EntryId/13/Implementing-A-SQL-Server-Database-With-The-Microsoft-Bot-Framework for an example of writing to the database. If you have further questions, please post them to the forums section on this site.

By Administrator on   12/14/2016 5:37 AM
Gravatar

Re: Introduction To FormFlow With The Microsoft Bot Framework

@ADefWebserver Yes, I already read and I already did it, it worked perfectly the recording in the database. Mine is in writing activity data and data that the user selected in FormBuilder . In MessagesController I can get the activity data, but I can not get the data from FormBuilder. And in FormBuilder, after .OnCompletion ... I can get the data that the user has entered, but I can not access the activity. How do I get the data from FormBuilder in the MessagesController?

By André on   12/14/2016 8:41 AM
Gravatar

Re: Introduction To FormFlow With The Microsoft Bot Framework

André - The blog comments are really bad for tracking a conversation, can you please make a post to the forums on this site? Thanks.

By Administrator on   12/14/2016 11:41 AM
Gravatar

Re: Introduction To FormFlow With The Microsoft Bot Framework

Hi, thanks a lot for providing such clean and step -by-step guide to understand bot development. It really helped clarifying certain doubts. But I need to know the major difference between FormFlow and Dialog. I need to develop an application where user is asked for problem statement , any supporting screenshots and also few categories. And this information is sent in some file format to other URL. I want to know which kind will be suitable for this project. How formflow is less flexible?

By Khushi on   1/11/2017 4:46 AM
Gravatar

Re: Introduction To FormFlow With The Microsoft Bot Framework

@Khushi - A FormFlow is composed of Dialogs, so Dialogs will always work. A FormFlow simply captures information, allows some logical branching, and allows users to ask about what information has been gathered. If you have complex requirements, I would just collect the information manually using Dialogs.

By Administrator on   1/11/2017 6:03 AM
Gravatar

Re: Introduction To FormFlow With The Microsoft Bot Framework

Thank you for the answer , I need help to create a PromptDialog with PromptChoice, I tried a lot with several types of hit and try but it did not give me any correct results. It would be great if you could create an article with sample codes using several Prompts(attachments, Choice etc). I have implemented Text and Confirm Prompts successfully till now. Hope you do not mind this request. :-)

By Khushi on   1/12/2017 6:49 AM
Gravatar

Re: Introduction To FormFlow With The Microsoft Bot Framework

@Khushi - I'm sorry but I wont have time to do that.

By Administrator on   1/12/2017 12:26 PM
Gravatar

Re: Introduction To FormFlow With The Microsoft Bot Framework

In reference to this aihelpwebsite.com/Blog/EntryId/8/Introduction-To-FormFlow-With-The-Microsoft-Bot-Framework How do we save data onto SQL DB. I have gone through aihelpwebsite.com/Blog/EntryId/13/Implementing-A-SQL-Server-Database-With-The-Microsoft-Bot-Framework
and was able to save the conversations to DB but when using the forms I'm not able to do so. Appreciate if you could tell me in achieving this.

By cherry123 on   2/15/2017 3:23 PM
Gravatar

Re: Introduction To FormFlow With The Microsoft Bot Framework

@cherry123 - Sorry but the only example I have is: aihelpwebsite.com/Blog/EntryId/13/Implementing-A-SQL-Server-Database-With-The-Microsoft-Bot-Framework However, it should have all the code you need.

By Administrator on   2/15/2017 4:06 PM
Gravatar

Re: Introduction To FormFlow With The Microsoft Bot Framework

Hi Admin, how can i convert the controller in such a way that after the profile has been created, and a greeting was already done like hi User welcome back! any suceeding message is then forwaded to QnaDialog and or Luis?

I tried adding this:

var boolProfileComplete = userData.GetProperty("ProfileComplete");
if (!boolProfileComplete)
{
// Call our FormFlow by calling MakeRootDialog
await Conversation.SendAsync(activity, MakeRootDialog);
}
else
{
//Check if Personalized Greeting is done
if (userData.GetProperty("Greet"))
{
ConnectorClient connector = new ConnectorClient(new Uri(activity.ServiceUrl));
await Conversation.SendAsync(activity, () => new QnADialog());
}
}

but the form dialog keeps on firing still.

By jay2_deguzman on   4/26/2017 10:12 PM
Gravatar

Re: Introduction To FormFlow With The Microsoft Bot Framework

@ jay2_deguzman - I cannot determine why it keeps firing. The best place for assistance is stackoverflow.com/questions/tagged/botframework.

By Administrator on   4/27/2017 4:10 AM