This is the bot series on ToDo Bot where we will be creating a Chatbot to create, view, and delete tasks. In this part, we are going to start coding the Main Dialog to show the above three options to the user for selection.
Video
Pre-requisites
- ToDo Bot | Part 1 | Setup the Development Environment | Microsoft Bot Framework
- ToDo Bot | Part 2 | Welcome Card | Adaptive Cards | Microsoft Bot Framework
Main Dialog
This will be the root dialog for all your sub dialogs. You can call any number of sub dialogs from here. Dialogs are nothing but a conversational flow. It is like a way of addressing your users sequentially.
We have used Waterfall dialog model to create our conversational flow. To learn more about it, watch the below video.
In the Main Dialog, we are going to show the users three options to select -> Create Task, View Task, and Delete Task. We will show these options using an Adaptive card. Also, we will be capturing the user response and sending it back to the user.
In Waterfall dialog model, we have used 3 steps –
- IntroStepAsync
- ActStepAsync
- FinalStepAsync
The first step will show the Adaptive card, the second step will capture the user response and send it to the user, and in the last step, we are restarting the Main Dialog.
This piece of code in the IntroStepAsync method will create an Adaptive card with 3 options and send it to the user.
private async Task<DialogTurnResult> IntroStepAsync(WaterfallStepContext stepContext, CancellationToken cancellationToken)
{
await stepContext.Context.SendActivityAsync(
MessageFactory.Text("What operation you would like to perform?"), cancellationToken);
List<string> operationList = new List<string> { "Create Task", "View Task", "Delete Task" };
// Create card
var card = new AdaptiveCard(new AdaptiveSchemaVersion(1, 0))
{
// Use LINQ to turn the choices into submit actions
Actions = operationList.Select(choice => new AdaptiveSubmitAction
{
Title = choice,
Data = choice, // This will be a string
}).ToList<AdaptiveAction>(),
};
// Prompt
return await stepContext.PromptAsync(nameof(ChoicePrompt), new PromptOptions
{
Prompt = (Activity)MessageFactory.Attachment(new Attachment
{
ContentType = AdaptiveCard.ContentType,
// Convert the AdaptiveCard to a JObject
Content = JObject.FromObject(card),
}),
Choices = ChoiceFactory.ToChoices(operationList),
// Don't render the choices outside the card
Style = ListStyle.None,
},
cancellationToken);
}
If you notice in the return statement, that we have used ChoicePrompt. Make sure you define in the constructor. Currently, TextPrompt is defined. Go ahead and define ChoicePrompt as well.
AddDialog(new ChoicePrompt(nameof(ChoicePrompt)));
AdaptiveCard will show an error, you will have to install the Nuget package AdaptiveCards and import it.
Below is the code for the ActStepAsync, that will capture the user response and send it back to the user.
private async Task<DialogTurnResult> ActStepAsync(WaterfallStepContext stepContext, CancellationToken cancellationToken)
{
stepContext.Values["Operation"] = ((FoundChoice)stepContext.Result).Value;
string operation = (string)stepContext.Values["Operation"];
await stepContext.Context.SendActivityAsync(MessageFactory.Text("You have selected - " + operation), cancellationToken);
return await stepContext.NextAsync(null, cancellationToken);
}
If you have followed Part 1 of this series, the last method remains the same, no changes. Below is the complete code of the MainDialog.cs.
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
//
// Generated with Bot Builder V4 SDK Template for Visual Studio CoreBot v4.11.1
using AdaptiveCards;
using Microsoft.Bot.Builder;
using Microsoft.Bot.Builder.Dialogs;
using Microsoft.Bot.Builder.Dialogs.Choices;
using Microsoft.Bot.Schema;
using Microsoft.Extensions.Logging;
using Newtonsoft.Json.Linq;
using System.Collections.Generic;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
namespace ToDoBot.Dialogs
{
public class MainDialog : ComponentDialog
{
private readonly ToDoLUISRecognizer _luisRecognizer;
protected readonly ILogger Logger;
// Dependency injection uses this constructor to instantiate MainDialog
public MainDialog(ToDoLUISRecognizer luisRecognizer, ILogger<MainDialog> logger)
: base(nameof(MainDialog))
{
_luisRecognizer = luisRecognizer;
Logger = logger;
AddDialog(new TextPrompt(nameof(TextPrompt)));
AddDialog(new ChoicePrompt(nameof(ChoicePrompt)));
AddDialog(new WaterfallDialog(nameof(WaterfallDialog), new WaterfallStep[]
{
IntroStepAsync,
ActStepAsync,
FinalStepAsync,
}));
// The initial child Dialog to run.
InitialDialogId = nameof(WaterfallDialog);
}
private async Task<DialogTurnResult> IntroStepAsync(WaterfallStepContext stepContext, CancellationToken cancellationToken)
{
await stepContext.Context.SendActivityAsync(
MessageFactory.Text("What operation you would like to perform?"), cancellationToken);
List<string> operationList = new List<string> { "Create Task", "View Task", "Delete Task" };
// Create card
var card = new AdaptiveCard(new AdaptiveSchemaVersion(1, 0))
{
// Use LINQ to turn the choices into submit actions
Actions = operationList.Select(choice => new AdaptiveSubmitAction
{
Title = choice,
Data = choice, // This will be a string
}).ToList<AdaptiveAction>(),
};
// Prompt
return await stepContext.PromptAsync(nameof(ChoicePrompt), new PromptOptions
{
Prompt = (Activity)MessageFactory.Attachment(new Attachment
{
ContentType = AdaptiveCard.ContentType,
// Convert the AdaptiveCard to a JObject
Content = JObject.FromObject(card),
}),
Choices = ChoiceFactory.ToChoices(operationList),
// Don't render the choices outside the card
Style = ListStyle.None,
},
cancellationToken);
}
private async Task<DialogTurnResult> ActStepAsync(WaterfallStepContext stepContext, CancellationToken cancellationToken)
{
stepContext.Values["Operation"] = ((FoundChoice)stepContext.Result).Value;
string operation = (string)stepContext.Values["Operation"];
await stepContext.Context.SendActivityAsync(MessageFactory.Text("You have selected - " + operation), cancellationToken);
return await stepContext.NextAsync(null, cancellationToken);
}
private async Task<DialogTurnResult> FinalStepAsync(WaterfallStepContext stepContext, CancellationToken cancellationToken)
{
// Restart the main dialog with a different message the second time around
var promptMessage = "What else can I do for you?";
return await stepContext.ReplaceDialogAsync(InitialDialogId, promptMessage, cancellationToken);
}
}
}
Go ahead and run the project. Below output you will be shown.

You must be logged in to post a comment.