Create a new bot dialog with Azure Bot Service

November 10, 2020

Here you can find how to create your own custom dialogs using Azure Bot Service.

Dialogs provide a way to manage a long-running conversation with the user. A dialog performs a task that can represent part of or a complete conversational thread. It can span just one turn or many, and can span a short or long period of time.


Start

In this example we will be using the core bot sample. You can grab the sample from the GitHub repo, or directly from Azure using this post.


Create

Create a new Class and called NewDialog.cs. In this example we will create a weather dialog. The bot asks about the location and the time of the forecast that the user would like. The question about the location happens in LocationStepAsync and the question about time, in TimeStepAsync. These are both TextPrompts, which means the users answers them using text, or speech if supported. The values given by the user are stored in the corresponding variables in the next step of each question. ConfirmStepAsync confirms that the values given by the user are correct using a ConfirmPrompt and FinalStepAsync ends or restarts the dialog according to the users choice in the previous step. You could add another step which answers with the weather, but you will need to connect to a weather API for that.

using System.Threading.Tasks;
using System.Threading;
using Microsoft.Bot.Builder;
using Microsoft.Bot.Builder.Dialogs;
using Microsoft.Bot.Schema;

namespace Microsoft.BotBuilderSamples.Dialogs
{
    public class NewDialog : ComponentDialog
    {
        public string Location { get; set; }
        public string Time { get; set; }

        public NewDialog()
            : base(nameof(NewDialog))
        {
            AddDialog(new TextPrompt(nameof(TextPrompt)));
            AddDialog(new ConfirmPrompt(nameof(ConfirmPrompt)));
            AddDialog(new WaterfallDialog(nameof(WaterfallDialog), new WaterfallStep[]
            {
                LocationStepAsync,
                TimeStepAsync,
                ConfirmStepAsync,
                FinalStepAsync,
            }));

            // The initial child Dialog to run.
            InitialDialogId = nameof(WaterfallDialog);
        }


        private async Task<DialogTurnResult> LocationStepAsync(WaterfallStepContext stepContext, CancellationToken cancellationToken)
        {
            var messageText = "What is your location?";
            var promptMessage = MessageFactory.Text(messageText, messageText, InputHints.ExpectingInput);
            return await stepContext.PromptAsync(nameof(TextPrompt), new PromptOptions { Prompt = promptMessage }, cancellationToken);
        }

        private async Task<DialogTurnResult> TimeStepAsync(WaterfallStepContext stepContext, CancellationToken cancellationToken)
        {
            Location = stepContext.Context.Activity.Text;

            var messageText = "Specify the time of the forecast";
            var promptMessage = MessageFactory.Text(messageText, messageText, InputHints.ExpectingInput);
            return await stepContext.PromptAsync(nameof(TextPrompt), new PromptOptions { Prompt = promptMessage }, cancellationToken);
        }

        private async Task<DialogTurnResult> ConfirmStepAsync(WaterfallStepContext stepContext, CancellationToken cancellationToken)
        {
            Time = stepContext.Context.Activity.Text;

            var messageText = $"Please confirm that you want the weather at {Location} for {Time}. Is this correct?";
            var promptMessage = MessageFactory.Text(messageText, messageText, InputHints.ExpectingInput);

            return await stepContext.PromptAsync(nameof(ConfirmPrompt), new PromptOptions { Prompt = promptMessage }, cancellationToken);
        }

        private async Task<DialogTurnResult> FinalStepAsync(WaterfallStepContext stepContext, CancellationToken cancellationToken)
        {
            if ((bool)stepContext.Result)
                return await stepContext.EndDialogAsync();
            else
                return await stepContext.BeginDialogAsync(nameof(NewDialog));
        }
    }
}


Connect

Open MainDialog.cs file and find this piece of code.

public MainDialog(FlightBookingRecognizer luisRecognizer, BookingDialog bookingDialog, ILogger<MainDialog> logger)
    : base(nameof(MainDialog))
{
    _luisRecognizer = luisRecognizer;
    Logger = logger;

    AddDialog(new TextPrompt(nameof(TextPrompt)));
    AddDialog(bookingDialog);
    AddDialog(new WaterfallDialog(nameof(WaterfallDialog), new WaterfallStep[]
    {
        IntroStepAsync,
        ActStepAsync,
        FinalStepAsync,
    }));

    // The initial child Dialog to run.
    InitialDialogId = nameof(WaterfallDialog);
}

Replace it with the followning one. Essentially you are adding NewDialog newDialog into the constructor’s arguments in line 1 and adding your dialog in line 9.

public MainDialog(FlightBookingRecognizer luisRecognizer, BookingDialog bookingDialog, NewDialog newDialog, ILogger<MainDialog> logger)
    : base(nameof(MainDialog))
{
    _luisRecognizer = luisRecognizer;
    Logger = logger;

    AddDialog(new TextPrompt(nameof(TextPrompt)));
    AddDialog(bookingDialog);
    AddDialog(newDialog);
    AddDialog(new WaterfallDialog(nameof(WaterfallDialog), new WaterfallStep[]
    {
        IntroStepAsync,
        ActStepAsync,
        FinalStepAsync,
    }));

    // The initial child Dialog to run.
    InitialDialogId = nameof(WaterfallDialog);
}

Go further down to the file and find the unhandled GetWeather intent ine the switch.

      case FlightBooking.Intent.GetWeather:
          // We haven't implemented the GetWeatherDialog so we just display a TODO message.
          var getWeatherMessageText = "TODO: get weather flow here";
          var getWeatherMessage = MessageFactory.Text(getWeatherMessageText, getWeatherMessageText, InputHints.IgnoringInput);
          await stepContext.Context.SendActivityAsync(getWeatherMessage, cancellationToken);
          break;

Replace it with this. Instead of prompting a placeholder message to the user, it will send the newly created dialog.

      case FlightBooking.Intent.GetWeather:
          return await stepContext.BeginDialogAsync(nameof(NewDialog));

Before we are done, you need to add your dialog in Startup.cs. Just open Startup.cs and add the following line.

      services.AddSingleton<NewDialog>();

After everithing is done, the finished dialog should look like this.


This is how you add your own dialogs to your bot!

About Me

Hi, my name is Demetris Bakas and I am a software engineer that loves to write code and be creative. I always find new technologies intriguing and I like to work with other people and be a part of a team. My goal is to develop software that people will find useful and will aid them in their everyday lives.
For any questions feel free to contact me at social media using the links below.