E-commerce Bot | Part 4 | Implementing the Email Authentication in Microsoft Bot Framework

In this bot series, we will create an E-commerce bot for one of the Online Chocolate Store “Naami Chocos“. This bot will have the following functionalities –

  1. Authentication
  2. Add to Cart
  3. Payment Integration
  4. FAQs using QnA Maker
  5. Connect the bot to the Facebook page

In this part, we will be implementing the Email Authentication by verifying the user’s email using an OTP in Microsoft Bot Framework.

Prerequisites

  1. Visual Studio
  2. Bot Framework Emulator
  3. Setup the Development Environment
  4. Welcome Card | Adaptive Cards
  5. Run Power Automate flow from the Postman using API
  6. How to Run Power Automate Flow using API in C#

The download links for the first two requirements are available on the Downloads Page. You can follow the 3rd & 4th requirement in the blog post or get the code to start your development on top of it. The 5th requirement is mandatory and the 6th one is optional.

Video

Final Product of this Demo

Define Waterfall Dialog Steps

Open Dialogs -> MainDialog.cs. Define the steps in the constructor for implementing some features of the bot and also create their respective methods.

public MainDialog(ILogger<MainDialog> logger, StateService stateService, UserRepository userRepository, IConfiguration configuration)
            : base(nameof(MainDialog))
        {
            _stateService = stateService ?? throw new System.ArgumentNullException(nameof(stateService));
            Logger = logger;
            _userRepository = userRepository;
            Configuration = configuration;

            AddDialog(new TextPrompt(nameof(TextPrompt)));
            AddDialog(new EmailAuthenticationDialog(_stateService, userRepository, Configuration));
            AddDialog(new WaterfallDialog(nameof(WaterfallDialog), new WaterfallStep[]
            {
                NameStepAsync,
                EmailAuthenticationStepAsync,
                IntroStepAsync,
                ActStepAsync,
                PaymentStepAsync,
                FinalStepAsync,
            }));

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

We need to define following properties in the MainDialog.cs.

protected readonly ILogger Logger;
private readonly StateService _stateService;
private readonly UserRepository _userRepository;
protected readonly IConfiguration Configuration;

Don’t worry about the UserRepository class for now. We will create it at a later stage. IConfiguration is used to get the key-value pairs from the appsettings.json file. In this file, we will store all our configuration details.

Create Email Authentication Sub Dialog

Create a new folder inside Dialogs and name it Operations. Create a new class file EmailAuthenticationDialog inside the Operations folder.

Derive the EmailAuthenticationDialog class from ComponentDialog class and import the Bot Builder Dialogs library.

using Microsoft.Bot.Builder.Dialogs;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;

namespace NaamiChocosBot.Dialogs.Operations
{
    public class EmailAuthenticationDialog : ComponentDialog
    {
    }
}

Define the Waterfall Dialog steps in EmailAuthenticationDialog constructor and create their respective methods in the class.

using Microsoft.Bot.Builder.Dialogs;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;

namespace NaamiChocosBot.Dialogs.Operations
{
    public class EmailAuthenticationDialog : ComponentDialog
    {
        public EmailAuthenticationDialog() : base(nameof(EmailAuthenticationDialog))
        {
            var waterfallSteps = new WaterfallStep[]
            {
                EmailStepAsync,
                OTPVerificationStepAsync,
                AuthenticationConfirmStepAsync,
            };

            AddDialog(new WaterfallDialog(nameof(WaterfallDialog), waterfallSteps));
            AddDialog(new TextPrompt(nameof(TextPrompt)));

            InitialDialogId = nameof(WaterfallDialog);
        }

        private Task<DialogTurnResult> EmailStepAsync(WaterfallStepContext stepContext, CancellationToken cancellationToken)
        {
            throw new NotImplementedException();
        }

        private Task<DialogTurnResult> OTPVerificationStepAsync(WaterfallStepContext stepContext, CancellationToken cancellationToken)
        {
            throw new NotImplementedException();
        }

        private Task<DialogTurnResult> AuthenticationConfirmStepAsync(WaterfallStepContext stepContext, CancellationToken cancellationToken)
        {
            throw new NotImplementedException();
        }
    }
}

We have defined 3 steps here –

  1. EmailStepAsync: Ask the user’s email
  2. OTPVerificationStepAsync: Send OTP to email and ask the user to verify the OTP
  3. AuthenticationConfirmStepAsync: Give a confirmation on the Email verification

Add the following properties inside the EmailAuthenticationDialog class and initialize them in the constructor.

private readonly StateService _stateService;
        private readonly UserRepository _userRespository;
        protected readonly IConfiguration Configuration;
        private readonly string EmailDialogID = "EmailDlg";
        private readonly string EmailVerificationCodeDialogID = "EmailVerificationCodeDlg";
        public EmailAuthenticationDialog(StateService stateService, UserRepository userRepository, IConfiguration configuration) : base(nameof(EmailAuthenticationDialog))
        {
            _stateService = stateService ?? throw new System.ArgumentNullException(nameof(stateService));
            _userRespository = userRepository;
            Configuration = configuration;

            var waterfallSteps = new WaterfallStep[]
            {
                EmailStepAsync,
                OTPVerificationStepAsync,
                AuthenticationConfirmStepAsync,
            };

            AddDialog(new WaterfallDialog(nameof(WaterfallDialog), waterfallSteps));
            AddDialog(new TextPrompt(nameof(TextPrompt)));
            AddDialog(new TextPrompt(EmailDialogID, EmailValidation));
            AddDialog(new NumberPrompt<int>(EmailVerificationCodeDialogID, EmailVerificationCodeValidation));

            InitialDialogId = nameof(WaterfallDialog);
        }

Below properties are used to validate the data provided by the user where we keep a track of the dialog id.

private readonly string EmailDialogID = "EmailDlg";
private readonly string EmailVerificationCodeDialogID = "EmailVerificationCodeDlg";

Implementing Email Authentication Dialog Steps

The first step is to ask the email of the user.

private async Task<DialogTurnResult> EmailStepAsync(WaterfallStepContext stepContext, CancellationToken cancellationToken)
        {

            await stepContext.Context.SendActivityAsync(MessageFactory.Text("Please Authenticate..."), cancellationToken);
            return await stepContext.PromptAsync(EmailDialogID, new PromptOptions
            {
                Prompt = MessageFactory.Text("Can I have your email address please?"),

            }, cancellationToken);
        }

Add a new method EmailValidation to validate the email structure.

private async Task<bool> EmailValidation(PromptValidatorContext<string> promptcontext, CancellationToken cancellationtoken)
        {
            string email = promptcontext.Recognized.Value;

            if (string.IsNullOrWhiteSpace(email))
            {
                await promptcontext.Context.SendActivityAsync("The email you entered is not valid, please enter a valid email.", cancellationToken: cancellationtoken);
                return false;
            }

            try
            {
                var addr = new System.Net.Mail.MailAddress(email);
                if (addr.Address == email)
                {
                    return true;
                }
                else
                {
                    await promptcontext.Context.SendActivityAsync("The email you entered is not valid, please enter a valid email.", cancellationToken: cancellationtoken);
                    return false;
                }
            }
            catch
            {
                await promptcontext.Context.SendActivityAsync("The email you entered is not valid, please enter a valid email.", cancellationToken: cancellationtoken);
                return false;
            }
        }

The second step will have the following actions –

  1. Capture the email address and save in the User Profile
  2. Generate the OTP
  3. Call the method which triggers the Power Automate flow to send email
  4. Ask the user to enter the OTP received
  5. Validate the OTP
private async Task<DialogTurnResult> OTPVerificationStepAsync(WaterfallStepContext stepContext, CancellationToken cancellationToken)
        {
            UserProfile userProfile = await _stateService.UserProfileAccessor.GetAsync(stepContext.Context, () => new UserProfile());
            
            // Save the email to user profile
            userProfile.Email = (string)stepContext.Result;

            // Generate the OTP and save it to the user profile
            Random rnd = new Random();
            userProfile.OTP = rnd.Next(100000, 999999);

            await _stateService.UserProfileAccessor.SetAsync(stepContext.Context, userProfile);

            await stepContext.Context.SendActivityAsync(MessageFactory.Text("Please wait while I send an OTP to your email for verification."), cancellationToken);

            // trigger the power automate flow to send email
            bool status = await _userRespository.SendEmailForCodeVerificationAsync(userProfile.OTP, userProfile.Email, userProfile.Name, Configuration["PowerAutomatePOSTURL"]);

            // verify the response status of the api call
            if (status)
            {
                return await stepContext.PromptAsync(EmailVerificationCodeDialogID, new PromptOptions
                {
                    Prompt = MessageFactory.Text("I have sent a verification code to your email. Please enter the code here to validate your email. Please Check your inbox or Spam folder for the email.")
                }, cancellationToken);
            }
            else
            {
                await stepContext.Context.SendActivityAsync(MessageFactory.Text("Verfication Email could not be sent. Please try again later. Sorry for the inconvenience caused."), cancellationToken);
                return await stepContext.EndDialogAsync(null, cancellationToken);
            }
            
        }

Add a new method EmailVerificationCodeValidation to validate the OTP entered by the user.

private async Task<bool> EmailVerificationCodeValidation(PromptValidatorContext<int> promptcontext, CancellationToken cancellationtoken)
        {
            UserProfile userProfile = await _stateService.UserProfileAccessor.GetAsync(promptcontext.Context, () => new UserProfile());
            int verificationCode = promptcontext.Recognized.Value;

            if (verificationCode == userProfile.OTP)
            {
                return true;
            }
            await promptcontext.Context.SendActivityAsync("The verification code you entered is incorrect. Please enter the correct code.", cancellationToken: cancellationtoken);
            return false;
        }

Update the Models -> UserProfile.cs to add few more properties. We are also declaring EmailVerified property with an initial value false. This is used to keep track of whether the email is verified or not.

public class UserProfile
    {
        public string Name { get; set; }
        public string Email { get; set; }
        public int OTP { get; set; }
        public bool EmailVerified { get; set; } = false;
    }

Create a new folder under the project directory with the name Utilities. Add a new class file UserRepository.cs. This class file will contain the code related to user operations.

Add the following code to the UserRepository.cs to trigger the Power Automate flow by calling an API.

using Newtonsoft.Json;
using System;
using System.Net.Http;
using System.Net.Http.Headers;
using System.Text;
using System.Threading.Tasks;

namespace NaamiChocosBot.Utilities
{
    public class UserRepository
    {
        public async Task<bool> SendEmailForCodeVerificationAsync(int verificationCode, string toAddress, string username, string uri)
        {
            try
            {
                HttpClient client = new HttpClient();
                client.BaseAddress = new Uri(uri);
                client.DefaultRequestHeaders.Accept.Clear();
                client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));

                HttpRequestMessage request = new HttpRequestMessage(HttpMethod.Post, client.BaseAddress);
                var body = $"{{\"emailAddress\": \"{toAddress}\",\"emailSubject\":\"[NaamiChocos] Email Verification Code\",\"userName\":\"{username}\",\"OTP\":\"{verificationCode}\"}}";
                var content = new StringContent(body, Encoding.UTF8, "application/json");
                request.Content = content;
                var response = await MakeRequestAsync(request, client);
                var authenticationModel = JsonConvert.DeserializeObject<AuthenticationModel>(response);

                if(authenticationModel.status.Equals("success"))
                {
                    return true;
                }
                else
                {
                    return false;
                }
            }
            catch (Exception e)
            {
                Console.WriteLine(e.Message);
                throw new Exception();
            }
        }

        public async Task<string> MakeRequestAsync(HttpRequestMessage getRequest, HttpClient client)
        {
            var response = await client.SendAsync(getRequest).ConfigureAwait(false);
            var responseString = string.Empty;
            try
            {
                response.EnsureSuccessStatusCode();
                responseString = await response.Content.ReadAsStringAsync().ConfigureAwait(false);
            }
            catch (HttpRequestException)
            {
                // empty responseString
            }

            return responseString;
        }
    }

    public class AuthenticationModel
    {
        public string status { get; set; }
        public string message { get; set; }
    }
}

The URI is present in the appsettings.json file. Provide your POST Request URI here which you got while creating the flow.

{
  "PowerAutomatePOSTURL": "<Your POST request URI from Power Automate>",
  "LuisAPIHostName": "",
  "LuisAPIKey": "",
  "LuisAppId": "",
  "MicrosoftAppId": "",
  "MicrosoftAppPassword": ""
}

Finally, the last step will update the EmailVerified property to true and end the dialog.

private async Task<DialogTurnResult> AuthenticationConfirmStepAsync(WaterfallStepContext stepContext, CancellationToken cancellationToken)
        {
            await stepContext.Context.SendActivityAsync(MessageFactory.Text("Your email is verified."), cancellationToken);
            UserProfile userProfile = await _stateService.UserProfileAccessor.GetAsync(stepContext.Context, () => new UserProfile());
            userProfile.EmailVerified = true;
            await _stateService.UserProfileAccessor.SetAsync(stepContext.Context, userProfile);
            return await stepContext.EndDialogAsync(null, cancellationToken);
        }

Below is the complete code of the EmailAuthenticationDialog.cs.

using Microsoft.Bot.Builder;
using Microsoft.Bot.Builder.Dialogs;
using Microsoft.Extensions.Configuration;
using NaamiChocosBot.Models;
using NaamiChocosBot.Services;
using NaamiChocosBot.Utilities;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;

namespace NaamiChocosBot.Dialogs.Operations
{
    public class EmailAuthenticationDialog : ComponentDialog
    {
        private readonly StateService _stateService;
        private readonly UserRepository _userRespository;
        protected readonly IConfiguration Configuration;
        private readonly string EmailDialogID = "EmailDlg";
        private readonly string EmailVerificationCodeDialogID = "EmailVerificationCodeDlg";
        public EmailAuthenticationDialog(StateService stateService, UserRepository userRepository, IConfiguration configuration) : base(nameof(EmailAuthenticationDialog))
        {
            _stateService = stateService ?? throw new System.ArgumentNullException(nameof(stateService));
            _userRespository = userRepository;
            Configuration = configuration;

            var waterfallSteps = new WaterfallStep[]
            {
                EmailStepAsync,
                OTPVerificationStepAsync,
                AuthenticationConfirmStepAsync,
            };

            AddDialog(new WaterfallDialog(nameof(WaterfallDialog), waterfallSteps));
            AddDialog(new TextPrompt(nameof(TextPrompt)));
            AddDialog(new TextPrompt(EmailDialogID, EmailValidation));
            AddDialog(new NumberPrompt<int>(EmailVerificationCodeDialogID, EmailVerificationCodeValidation));

            InitialDialogId = nameof(WaterfallDialog);
        }

        private async Task<DialogTurnResult> EmailStepAsync(WaterfallStepContext stepContext, CancellationToken cancellationToken)
        {

            await stepContext.Context.SendActivityAsync(MessageFactory.Text("Please Authenticate..."), cancellationToken);
            return await stepContext.PromptAsync(EmailDialogID, new PromptOptions
            {
                Prompt = MessageFactory.Text("Can I have your email address please?"),

            }, cancellationToken);
        }

        private async Task<DialogTurnResult> OTPVerificationStepAsync(WaterfallStepContext stepContext, CancellationToken cancellationToken)
        {
            UserProfile userProfile = await _stateService.UserProfileAccessor.GetAsync(stepContext.Context, () => new UserProfile());
            
            // Save the email to user profile
            userProfile.Email = (string)stepContext.Result;

            // Generate the OTP and save it to the user profile
            Random rnd = new Random();
            userProfile.OTP = rnd.Next(100000, 999999);

            await _stateService.UserProfileAccessor.SetAsync(stepContext.Context, userProfile);

            await stepContext.Context.SendActivityAsync(MessageFactory.Text("Please wait while I send an OTP to your email for verification."), cancellationToken);

            // trigger the power automate flow to send email
            bool status = await _userRespository.SendEmailForCodeVerificationAsync(userProfile.OTP, userProfile.Email, userProfile.Name, Configuration["PowerAutomatePOSTURL"]);

            // verify the response status of the api call
            if (status)
            {
                return await stepContext.PromptAsync(EmailVerificationCodeDialogID, new PromptOptions
                {
                    Prompt = MessageFactory.Text("I have sent a verification code to your email. Please enter the code here to validate your email. Please Check your inbox or Spam folder for the email.")
                }, cancellationToken);
            }
            else
            {
                await stepContext.Context.SendActivityAsync(MessageFactory.Text("Verfication Email could not be sent. Please try again later. Sorry for the inconvenience caused."), cancellationToken);
                return await stepContext.EndDialogAsync(null, cancellationToken);
            }
            
            
        }

        private async Task<DialogTurnResult> AuthenticationConfirmStepAsync(WaterfallStepContext stepContext, CancellationToken cancellationToken)
        {
            await stepContext.Context.SendActivityAsync(MessageFactory.Text("Your email is verified."), cancellationToken);
            UserProfile userProfile = await _stateService.UserProfileAccessor.GetAsync(stepContext.Context, () => new UserProfile());
            userProfile.EmailVerified = true;
            await _stateService.UserProfileAccessor.SetAsync(stepContext.Context, userProfile);
            return await stepContext.EndDialogAsync(null, cancellationToken);
        }

        private async Task<bool> EmailValidation(PromptValidatorContext<string> promptcontext, CancellationToken cancellationtoken)
        {
            string email = promptcontext.Recognized.Value;

            if (string.IsNullOrWhiteSpace(email))
            {
                await promptcontext.Context.SendActivityAsync("The email you entered is not valid, please enter a valid email.", cancellationToken: cancellationtoken);
                return false;
            }

            try
            {
                var addr = new System.Net.Mail.MailAddress(email);
                if (addr.Address == email)
                {
                    return true;
                }
                else
                {
                    await promptcontext.Context.SendActivityAsync("The email you entered is not valid, please enter a valid email.", cancellationToken: cancellationtoken);
                    return false;
                }
            }
            catch
            {
                await promptcontext.Context.SendActivityAsync("The email you entered is not valid, please enter a valid email.", cancellationToken: cancellationtoken);
                return false;
            }
        }

        private async Task<bool> EmailVerificationCodeValidation(PromptValidatorContext<int> promptcontext, CancellationToken cancellationtoken)
        {
            UserProfile userProfile = await _stateService.UserProfileAccessor.GetAsync(promptcontext.Context, () => new UserProfile());
            int verificationCode = promptcontext.Recognized.Value;

            if (verificationCode == userProfile.OTP)
            {
                return true;
            }
            await promptcontext.Context.SendActivityAsync("The verification code you entered is incorrect. Please enter the correct code.", cancellationToken: cancellationtoken);
            return false;
        }
    }
}

With this, we move to the MainDialog.cs and verify if the email is verified.

Updating the Main Dialog and implementing the EmailAuthenticationStepAsync

The second step in MainDialog.cs will have the following actions –

  1. Save the user name in the user profile
  2. Begin the email authentication dialog
  3. If the user name & email is present in the bot state and email is not verified, then begin the email authentication dialog
  4. If the user name and email are present and the email is verified, then greet the user.
private async Task<DialogTurnResult> EmailAuthenticationStepAsync(WaterfallStepContext stepContext, CancellationToken cancellationToken)
        {
            UserProfile userProfile = await _stateService.UserProfileAccessor.GetAsync(stepContext.Context, () => new UserProfile());
            if (string.IsNullOrEmpty(userProfile.Name))
            {
                userProfile.Name = (string)stepContext.Result;

                await _stateService.UserProfileAccessor.SetAsync(stepContext.Context, userProfile);
            }


            if (string.IsNullOrEmpty(userProfile.Email))
            {
                return await stepContext.BeginDialogAsync(nameof(EmailAuthenticationDialog), null, cancellationToken);
            }
            else
            {   
                if(userProfile.EmailVerified)
                {
                    await stepContext.Context.SendActivityAsync(MessageFactory.Text($"Welcome back {userProfile.Name}, How can I help you today?"), cancellationToken);
                    return await stepContext.NextAsync(null, cancellationToken);
                }
                else
                {
                    await stepContext.Context.SendActivityAsync(MessageFactory.Text($"Hello {userProfile.Name}, Your email is not verified."), cancellationToken);
                    return await stepContext.BeginDialogAsync(nameof(EmailAuthenticationDialog), null, cancellationToken);
                }
                
            }
        }

The complete code of the MainDialog.cs is look like this.

// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
//
// Generated with Bot Builder V4 SDK Template for Visual Studio CoreBot v4.13.1

using Microsoft.Bot.Builder;
using Microsoft.Bot.Builder.Dialogs;
using Microsoft.Bot.Schema;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.Logging;
using Microsoft.Recognizers.Text.DataTypes.TimexExpression;
using NaamiChocosBot.Dialogs.Operations;
using NaamiChocosBot.Models;
using NaamiChocosBot.Services;
using NaamiChocosBot.Utilities;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;

namespace NaamiChocosBot.Dialogs
{
    public class MainDialog : ComponentDialog
    {

        protected readonly ILogger Logger;
        private readonly StateService _stateService;
        private readonly UserRepository _userRepository;
        protected readonly IConfiguration Configuration;

        // Dependency injection uses this constructor to instantiate MainDialog
        public MainDialog(ILogger<MainDialog> logger, StateService stateService, UserRepository userRepository, IConfiguration configuration)
            : base(nameof(MainDialog))
        {
            _stateService = stateService ?? throw new System.ArgumentNullException(nameof(stateService));
            Logger = logger;
            _userRepository = userRepository;
            Configuration = configuration;

            AddDialog(new TextPrompt(nameof(TextPrompt)));
            AddDialog(new EmailAuthenticationDialog(_stateService, userRepository, Configuration));
            AddDialog(new WaterfallDialog(nameof(WaterfallDialog), new WaterfallStep[]
            {
                NameStepAsync,
                EmailAuthenticationStepAsync,
                IntroStepAsync,
                ActStepAsync,
                PaymentStepAsync,
                FinalStepAsync,
            }));

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

        private async Task<DialogTurnResult> NameStepAsync(WaterfallStepContext stepContext, CancellationToken cancellationToken)
        {
            UserProfile userProfile = await _stateService.UserProfileAccessor.GetAsync(stepContext.Context, () => new UserProfile());
            if (string.IsNullOrEmpty(userProfile.Name))
            {
                return await stepContext.PromptAsync(nameof(TextPrompt), new PromptOptions
                {
                    Prompt = MessageFactory.Text("What is your name?")
                }, cancellationToken);
            }
            else
            {
                return await stepContext.NextAsync(null, cancellationToken);
            }
        }

        private async Task<DialogTurnResult> EmailAuthenticationStepAsync(WaterfallStepContext stepContext, CancellationToken cancellationToken)
        {
            UserProfile userProfile = await _stateService.UserProfileAccessor.GetAsync(stepContext.Context, () => new UserProfile());
            if (string.IsNullOrEmpty(userProfile.Name))
            {
                userProfile.Name = (string)stepContext.Result;

                await _stateService.UserProfileAccessor.SetAsync(stepContext.Context, userProfile);
            }


            if (string.IsNullOrEmpty(userProfile.Email))
            {
                return await stepContext.BeginDialogAsync(nameof(EmailAuthenticationDialog), null, cancellationToken);
            }
            else
            {   
                if(userProfile.EmailVerified)
                {
                    await stepContext.Context.SendActivityAsync(MessageFactory.Text($"Welcome back {userProfile.Name}, How can I help you today?"), cancellationToken);
                    return await stepContext.NextAsync(null, cancellationToken);
                }
                else
                {
                    await stepContext.Context.SendActivityAsync(MessageFactory.Text($"Hello {userProfile.Name}, Your email is not verified."), cancellationToken);
                    return await stepContext.BeginDialogAsync(nameof(EmailAuthenticationDialog), null, cancellationToken);
                }
                
            }
        }

        private async Task<DialogTurnResult> IntroStepAsync(WaterfallStepContext stepContext, CancellationToken cancellationToken)
        {
            return await stepContext.NextAsync(null, cancellationToken);
        }

        private async Task<DialogTurnResult> ActStepAsync(WaterfallStepContext stepContext, CancellationToken cancellationToken)
        {
            return await stepContext.NextAsync(null, cancellationToken);
        }

        private async Task<DialogTurnResult> PaymentStepAsync(WaterfallStepContext stepContext, CancellationToken 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);
            return await stepContext.EndDialogAsync(null, cancellationToken);
        }
    }
}

Update the Startup.cs file to register the services.

// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
//
// Generated with Bot Builder V4 SDK Template for Visual Studio CoreBot v4.13.1

using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.Bot.Builder;
using Microsoft.Bot.Builder.BotFramework;
using Microsoft.Bot.Builder.Integration.AspNet.Core;
using Microsoft.Bot.Connector.Authentication;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;

using NaamiChocosBot.Bots;
using NaamiChocosBot.Dialogs;
using NaamiChocosBot.Services;
using NaamiChocosBot.Utilities;

namespace NaamiChocosBot
{
    public class Startup
    {
        // This method gets called by the runtime. Use this method to add services to the container.
        public void ConfigureServices(IServiceCollection services)
        {
            services.AddControllers().AddNewtonsoftJson();

            // Create the Bot Framework Adapter with error handling enabled.
            services.AddSingleton<IBotFrameworkHttpAdapter, AdapterWithErrorHandler>();

            services.AddSingleton<ICredentialProvider, ConfigurationCredentialProvider>();

            // Configure State
            ConfigureState(services);

            // The MainDialog that will be run by the bot.
            services.AddSingleton<MainDialog>();

            services.AddSingleton<UserRepository>();

            // Create the bot as a transient. In this case the ASP Controller is expecting an IBot.
            services.AddTransient<IBot, DialogAndWelcomeBot<MainDialog>>();
        }

        public void ConfigureState(IServiceCollection services)
        {
            // Create the storage we'll be using for User and Conversation state. (Memory is great for testing purposes.)
            services.AddSingleton<IStorage, MemoryStorage>();

            // Create the User state. (Used in this bot's Dialog implementation.)
            services.AddSingleton<UserState>();

            // Create the Conversation state. (Used by the Dialog system itself.)
            services.AddSingleton<ConversationState>();

            // Create an instance of the state service
            services.AddSingleton<StateService>();
        }

        // This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
        public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
        {
            if (env.IsDevelopment())
            {
                app.UseDeveloperExceptionPage();
            }

            app.UseDefaultFiles()
                .UseStaticFiles()
                .UseWebSockets()
                .UseRouting()
                .UseAuthorization()
                .UseEndpoints(endpoints =>
                {
                    endpoints.MapControllers();
                });

            // app.UseHttpsRedirection();
        }
    }
}

Get the complete code for this demo from the GitHub Repository.

Thank you All!!! Hope you find this useful.


Leave a Reply

Up ↑

Discover more from JD Bots

Subscribe now to keep reading and get access to the full archive.

Continue reading