Bot Builder v4 HOL
Chapter 1: Preparation
• Visual Studio 2017
• .Net Core 2.x ( https://www.microsoft.com/net/download )
• Bot Builder V4 SDK Template for Visual Studio
( https://marketplace.visualstudio.com/items?itemName=BotBuilder.botb
uilderv4 )
• Bot Emulator ( https://github.com/Microsoft/BotFramework-
Emulator/releases )
• Ngrok (https://ngrok.com/ )
Or
You can use Azure Bot Services .
After Download the Ngrok, please launch your Bot Emulator and go to
Emulator Settings and Setup as below.
Chapter 2: Create Project
1. Launch your Visual Studio.
2. Create a New Project, File > New > Project
3. Select Multi-Project and Select Bot Builder Echo Bot v4 and Name
your project, HandsonBot . Lastly , click OK button.
4. Make sure your bot template update to the v4.0.7
5. Test Run your project. Go to dropdownlist of IIS Express and Select
HandsonBot , which is your project name and Press F5 for Debug your
project.
6. After Debug, you will see the localhost as below.
7. Launch your Bot Framework Emulator and Click Open Bot and Select
BotConfiguration.Bot that in your project.
Chapter 3: Implementation of welcome message
1. Go to your project, right click > add new folder “SampleBot”.
2. After create the folder , right click > add class > name the class as
“SampleBot”.
3. Implement the code as below.
using Microsoft.Bot.Builder;
using Microsoft.Bot.Builder.Dialogs;
using Microsoft.Bot.Schema;
using Microsoft.Extensions.Logging;
using System;
using System.Threading;
using System.Threading.Tasks;
namespace HandsonBot.SampleBot
{
public class SampleBot : IBot
{
private const string WelcomeText = "Welcome to Sample Bot";
private readonly ILogger _logger;
private readonly SampleBotAccessors _accessors; // Added
private readonly DialogSet _dialogs; // Added
public SampleBot(SampleBotAccessors accessors, ILoggerFactory
loggerFactory) // Updated
{
_accessors = accessors ?? throw new
ArgumentException(nameof(accessors)); // Added
_dialogs = new DialogSet(accessors.ConversationDialogState); // Added
_dialogs.Add(new TextPrompt("name", ValidateHandleNameAsync));
_logger = loggerFactory.CreateLogger<SampleBot>();
_logger.LogInformation("Start SampleBot");
}
private Task<bool> ValidateHandleNameAsync(PromptValidatorContext<string>
promptContext, CancellationToken cancellationToken)
{
var result = promptContext.Recognized.Value;
if (result != null && result.Length >= 3)
{
var upperValue = result.ToUpperInvariant();
promptContext.Recognized.Value = upperValue;
return Task.FromResult(true);
}
return Task.FromResult(false);
}
public async Task OnTurnAsync(ITurnContext turnContext, CancellationToken
cancellationToken = default(CancellationToken))
{
if (turnContext.Activity.Type == ActivityTypes.Message)
{
// We will exchange normal messages here.
await SendMessageActivityAsync(turnContext, cancellationToken); //
updated
}
else if (turnContext.Activity.Type ==
ActivityTypes.ConversationUpdate)
{
await SendWelcomeMessageAsync(turnContext, cancellationToken);
}
else
{
_logger.LogInformation($"passed:{turnContext.Activity.Type}");
}
await _accessors.ConversationState.SaveChangesAsync(turnContext,
false, cancellationToken);
await _accessors.UserState.SaveChangesAsync(turnContext, false,
cancellationToken);
}
private static async Task SendWelcomeMessageAsync(ITurnContext
turnContext, CancellationToken cancellationToken)
{
foreach (var member in turnContext.Activity.MembersAdded)
{
if (member.Id != turnContext.Activity.Recipient.Id)
{
await turnContext.SendActivityAsync(WelcomeText,
cancellationToken: cancellationToken);
}
}
}
private async Task SendMessageActivityAsync(ITurnContext turnContext,
CancellationToken cancellationToken)
{
var dialogContext = await _dialogs.CreateContextAsync(turnContext,
cancellationToken);
var dialogTurnResult = await
dialogContext.ContinueDialogAsync(cancellationToken);
var userProfile = await _accessors.UserProfile.GetAsync(turnContext,
() => new UserProfile(), cancellationToken);
// If the handle name is not registered in UserState
if (userProfile.HandleName == null)
{
await GetHandleNameAsync(dialogContext, dialogTurnResult,
userProfile, cancellationToken);
}
else
{
await turnContext.SendActivityAsync($"Hello
{userProfile.HandleName}", cancellationToken: cancellationToken);
}
}
private async Task GetHandleNameAsync(DialogContext dialogContext,
DialogTurnResult dialogTurnResult, UserProfile userProfile, CancellationToken
cancellationToken)
{
if (dialogTurnResult.Status is DialogTurnStatus.Empty)
{
await dialogContext.PromptAsync(
"name",
new PromptOptions
{
Prompt = MessageFactory.Text("Please tell me your handle
name first."),
RetryPrompt = MessageFactory.Text("The handle name must be
at least 3 words long."),
},
cancellationToken);
}
else if (dialogTurnResult.Status is DialogTurnStatus.Complete)
{
// Register your handle name with UserState
userProfile.HandleName = (string)dialogTurnResult.Result;
_logger.LogInformation($"Handle Name registration:
{userProfile.HandleName}");
}
}
}
}
4. Go to Startup.cs
Change near line 57
From
services.AddBot<EchoWithCounterBot>(options =>
to
services.AddBot<SampleBot.SampleBot>(options =>
&
Change near line 78
From
ILogger logger = _loggerFactory.CreateLogger<EchoWithCounterBot>();
to
ILogger logger = _loggerFactory.CreateLogger<SampleBot.SampleBot>();
Chapter 4: State Management
1. Right Click “SampleBot” Folder > right click > Add > Create
UserProfile.class and Implement the code as below.
namespace HandsonBot.SampleBot
{
public class UserProfile
{
public string HandleName { get; set; }
}
}
2. Install the Microsoft.Bot.Builder.Dialogs Nuget Package.
Go to Tools> Nuget Package Manager> Package Manager Console and
type the command as below.
Install-Package Microsoft.Bot.Builder.Dialogs
3. Implement of State management Accessor
Right Click “SampleBot” Folder > right click > Add > Create
SampleBotAccessors.class and Implement the code as below.
using System;
using Microsoft.Bot.Builder;
using Microsoft.Bot.Builder.Dialogs;
namespace HandsonBot.SampleBot
{
public class SampleBotAccessors
{
public IStatePropertyAccessor<DialogState> ConversationDialogState { get;
set; }
public IStatePropertyAccessor<UserProfile> UserProfile { get; set; }
public ConversationState ConversationState { get; }
public UserState UserState { get; }
public SampleBotAccessors(ConversationState conversationState, UserState
userState)
{
ConversationState = conversationState ?? throw new
ArgumentNullException(nameof(conversationState));
UserState = userState ?? throw new ArgumentException(nameof(userState));
}
}
}
4. Change Startup.cs near line 111, to implement Application of UserState
Class
From
var conversationState = new ConversationState(dataStore);
options.State.Add(conversationState);
To
var conversationState = new ConversationState(dataStore);
options.State.Add(conversationState);
var userState = new UserState(dataStore);
options.State.Add(userState);
5. Implement of SampleBotAccessors class in Startup.cs , add the following
code as below.
using System;
using System.Linq;
using HandsonBot.SampleBot;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.Bot.Builder;
using Microsoft.Bot.Builder.Dialogs;
using Microsoft.Bot.Builder.Integration;
using Microsoft.Bot.Builder.Integration.AspNet.Core;
using Microsoft.Bot.Configuration;
using Microsoft.Bot.Connector.Authentication;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;
namespace HandsonBot
{
/// <summary>
/// The Startup class configures services and the request
pipeline.
/// </summary>
public class Startup
{
private ILoggerFactory _loggerFactory;
private bool _isProduction = false;
public Startup(IHostingEnvironment env)
{
_isProduction = env.IsProduction();
var builder = new ConfigurationBuilder()
.SetBasePath(env.ContentRootPath)
.AddJsonFile("appsettings.json", optional: true,
reloadOnChange: true)
.AddJsonFile($"appsettings.{env.EnvironmentName}.json"
, optional: true)
.AddEnvironmentVariables();
Configuration = builder.Build();
}
/// <summary>
/// Gets the configuration that represents a set of key/value
application configuration properties.
/// </summary>
/// <value>
/// The <see cref="IConfiguration"/> that represents a set of
key/value application configuration properties.
/// </value>
public IConfiguration Configuration { get; }
/// <summary>
/// This method gets called by the runtime. Use this method to
add services to the container.
/// </summary>
/// <param name="services">The <see
cref="IServiceCollection"/> specifies the contract for a collection of
service descriptors.</param>
/// <seealso cref="IStatePropertyAccessor{T}"/>
/// <seealso cref="https://docs.microsoft.com/en-
us/aspnet/web-api/overview/advanced/dependency-injection"/>
/// <seealso cref="https://docs.microsoft.com/en-us/azure/bot-
service/bot-service-manage-channels?view=azure-bot-service-4.0"/>
public void ConfigureServices(IServiceCollection services)
{
services.AddBot<SampleBot.SampleBot>(options =>
{
var secretKey =
Configuration.GetSection("botFileSecret")?.Value;
var botFilePath =
Configuration.GetSection("botFilePath")?.Value;
// Loads .bot configuration file and adds a singleton
that your Bot can access through dependency injection.
var botConfig = BotConfiguration.Load(botFilePath ??
@".BotConfiguration.bot", secretKey);
services.AddSingleton(sp => botConfig ?? throw new
InvalidOperationException($"The .bot config file could not be loaded.
({botConfig})"));
// Retrieve current endpoint.
var environment = _isProduction ? "production" :
"development";
var service = botConfig.Services.Where(s => s.Type ==
"endpoint" && s.Name == environment).FirstOrDefault();
if (!(service is EndpointService endpointService))
{
throw new InvalidOperationException($"The .bot
file does not contain an endpoint with name '{environment}'.");
}
options.CredentialProvider = new
SimpleCredentialProvider(endpointService.AppId,
endpointService.AppPassword);
// Creates a logger for the application to use.
ILogger logger =
_loggerFactory.CreateLogger<SampleBot.SampleBot>();
// Catches any errors that occur during a conversation
turn and logs them.
options.OnTurnError = async (context, exception) =>
{
logger.LogError($"Exception caught :
{exception}");
await context.SendActivityAsync("Sorry, it looks
like something went wrong.");
};
// The Memory Storage used here is for local bot
debugging only. When the bot
// is restarted, everything stored in memory will be
gone.
IStorage dataStore = new MemoryStorage();
// For production bots use the Azure Blob or
// Azure CosmosDB storage providers. For the Azure
// based storage providers, add the
Microsoft.Bot.Builder.Azure
// Nuget package to your solution. That package is
found at:
//
https://www.nuget.org/packages/Microsoft.Bot.Builder.Azure/
// Uncomment the following lines to use Azure Blob
Storage
// //Storage configuration name or ID from the .bot
file.
// const string StorageConfigurationId = "<STORAGE-
NAME-OR-ID-FROM-BOT-FILE>";
// var blobConfig =
botConfig.FindServiceByNameOrId(StorageConfigurationId);
// if (!(blobConfig is BlobStorageService
blobStorageConfig))
// {
// throw new InvalidOperationException($"The .bot
file does not contain an blob storage with name
'{StorageConfigurationId}'.");
// }
// // Default container name.
// const string DefaultBotContainer = "<DEFAULT-
CONTAINER>";
// var storageContainer =
string.IsNullOrWhiteSpace(blobStorageConfig.Container) ?
DefaultBotContainer : blobStorageConfig.Container;
// IStorage dataStore = new
Microsoft.Bot.Builder.Azure.AzureBlobStorage(blobStorageConfig.Connect
ionString, storageContainer);
// Create Conversation State object.
// The Conversation State object is where we persist
anything at the conversation-scope.
var conversationState = new
ConversationState(dataStore);
options.State.Add(conversationState);
var userState = new UserState(dataStore);
options.State.Add(userState);
});
// Create and register state accesssors.
// Acessors created here are passed into the IBot-derived
class on every turn.
services.AddSingleton<EchoBotAccessors>(sp =>
{
var options =
sp.GetRequiredService<IOptions<BotFrameworkOptions>>().Value;
if (options == null)
{
throw new
InvalidOperationException("BotFrameworkOptions must be configured
prior to setting up the state accessors");
}
var conversationState =
options.State.OfType<ConversationState>().FirstOrDefault();
if (conversationState == null)
{
throw new
InvalidOperationException("ConversationState must be defined and added
before adding conversation-scoped state accessors.");
}
// Create the custom state accessor.
// State accessors enable other components to read and
write individual properties of state.
var accessors = new
EchoBotAccessors(conversationState)
{
CounterState =
conversationState.CreateProperty<CounterState>(EchoBotAccessors.Counte
rStateName),
};
return accessors;
});
// Create and register state accesssors.
// Acessors created here are passed into the IBot-derived
class on every turn.
services.AddSingleton<SampleBotAccessors>(sp =>
{
var options =
sp.GetRequiredService<IOptions<BotFrameworkOptions>>().Value
?? throw new
InvalidOperationException("BotFrameworkOptions must be configured
prior to setting up the state accessors");
var conversationState =
options.State.OfType<ConversationState>().FirstOrDefault()
?? throw new
InvalidOperationException("ConversationState が ConfigureServices で設
定されていません。");
var userState =
options.State.OfType<UserState>().FirstOrDefault()
?? throw new
InvalidOperationException("UserState が ConfigureServices で設定されてい
ません。");
var accessors = new
SampleBotAccessors(conversationState, userState)
{
ConversationDialogState =
conversationState.CreateProperty<DialogState>(nameof(DialogState)),
UserProfile =
userState.CreateProperty<UserProfile>(nameof(UserProfile)),
};
return accessors;
});
}
public void Configure(IApplicationBuilder app,
IHostingEnvironment env, ILoggerFactory loggerFactory)
{
_loggerFactory = loggerFactory;
app.UseDefaultFiles()
.UseStaticFiles()
.UseBotFramework();
}
}
}
6. Go back to SampleBot.cs added the following code with comment and
Waterfallsteps.
//Added: Part where code is added
//Updated: Changing parts
using Microsoft.Bot.Builder;
using Microsoft.Bot.Builder.Dialogs;
using Microsoft.Bot.Schema;
using Microsoft.Extensions.Logging;
using System;
using System.Threading;
using System.Threading.Tasks;
namespace HandsonBot.SampleBot
{
public class SampleBot : IBot
{
private const string WelcomeText = "Welcome to Sample Bot";
private readonly ILogger _logger;
private readonly SampleBotAccessors _accessors; // Added
private readonly DialogSet _dialogs; // Added
public SampleBot(SampleBotAccessors accessors, ILoggerFactory
loggerFactory)
{
_accessors = accessors ?? throw new
ArgumentException(nameof(accessors));
_dialogs = new DialogSet(accessors.ConversationDialogState);
var waterfallSteps = new WaterfallStep[]
{
ConfirmAgeStepAsync,
ExecuteAgeStepAsync,
ExecuteFinalConfirmStepAsync,
ExecuteSummaryStepAsync,
};
_dialogs.Add(new TextPrompt("name", ValidateHandleNameAsync));
_dialogs.Add(new ConfirmPrompt("confirm"));
_dialogs.Add(new NumberPrompt<int>("age"));
_dialogs.Add(new WaterfallDialog("details", waterfallSteps));
_logger = loggerFactory.CreateLogger<SampleBot>();
_logger.LogInformation("Start SampleBot");
}
private async Task GetHandleNameAsync(DialogContext dialogContext,
DialogTurnResult dialogTurnResult, UserProfile userProfile,
CancellationToken cancellationToken)
{
if (dialogTurnResult.Status is DialogTurnStatus.Empty)
{
await dialogContext.PromptAsync(
"name",
new PromptOptions
{
Prompt = MessageFactory.Text("Please tell me your
handle name first."),
RetryPrompt = MessageFactory.Text("The handle name
must be at least 3 words long."),
},
cancellationToken);
}
// If you enter a handle name
else if (dialogTurnResult.Status is DialogTurnStatus.Complete)
{
if (dialogTurnResult.Result != null)
{
// Register your handle name with UserState
userProfile.HandleName =
(string)dialogTurnResult.Result;
await dialogContext.BeginDialogAsync("details", null,
cancellationToken); // added
}
}
}
private Task<bool>
ValidateHandleNameAsync(PromptValidatorContext<string> promptContext,
CancellationToken cancellationToken)
{
var result = promptContext.Recognized.Value;
if (result != null && result.Length >= 3)
{
var upperValue = result.ToUpperInvariant();
promptContext.Recognized.Value = upperValue;
return Task.FromResult(true);
}
return Task.FromResult(false);
}
public async Task OnTurnAsync(ITurnContext turnContext,
CancellationToken cancellationToken = default(CancellationToken))
{
if (turnContext.Activity.Type == ActivityTypes.Message)
{
// We will exchange normal messages here.
await SendMessageActivityAsync(turnContext,
cancellationToken); // updated
}
else if (turnContext.Activity.Type ==
ActivityTypes.ConversationUpdate)
{
await SendWelcomeMessageAsync(turnContext,
cancellationToken);
}
else
{
_logger.LogInformation($"passed:{turnContext.Activity.Type}");
}
await
_accessors.ConversationState.SaveChangesAsync(turnContext, false,
cancellationToken);
await _accessors.UserState.SaveChangesAsync(turnContext, false,
cancellationToken);
}
private static async Task SendWelcomeMessageAsync(ITurnContext
turnContext, CancellationToken cancellationToken)
{
foreach (var member in turnContext.Activity.MembersAdded)
{
if (member.Id != turnContext.Activity.Recipient.Id)
{
await turnContext.SendActivityAsync(WelcomeText,
cancellationToken: cancellationToken);
}
}
}
public async Task SendMessageActivityAsync(ITurnContext
turnContext, CancellationToken cancellationToken)
{
var dialogContext = await
_dialogs.CreateContextAsync(turnContext, cancellationToken);
var dialogTurnResult = await
dialogContext.ContinueDialogAsync(cancellationToken);
var userProfile = await
_accessors.UserProfile.GetAsync(turnContext, () => new UserProfile(),
cancellationToken);
// If the handle name is not registered in UserState
if (userProfile.HandleName == null)
{
await GetHandleNameAsync(dialogContext, dialogTurnResult,
userProfile, cancellationToken);
}
// If you have a handle name registered with UserState
else
{
// added
if (dialogTurnResult.Status == DialogTurnStatus.Empty)
{
await dialogContext.BeginDialogAsync("details", null,
cancellationToken);
}
}
}
//----------------------------------------------
//Lab
private async Task<DialogTurnResult>
ConfirmAgeStepAsync(WaterfallStepContext stepContext, CancellationToken
cancellationToken)
{
var userProfile = await
_accessors.UserProfile.GetAsync(stepContext.Context, () => new
UserProfile(), cancellationToken);
return await stepContext.PromptAsync(
"confirm",
new PromptOptions
{
Prompt = MessageFactory.Text($"{userProfile.HandleName}
May I ask your age?"),
RetryPrompt = MessageFactory.Text("Answer yes or No."),
},
cancellationToken);
}
private async Task<DialogTurnResult>
ExecuteAgeStepAsync(WaterfallStepContext stepContext, CancellationToken
cancellationToken)
{
if ((bool)stepContext.Result)
{
return await stepContext.PromptAsync(
"age",
new PromptOptions
{
Prompt = MessageFactory.Text("What is your age?"),
RetryPrompt = MessageFactory.Text("Enter the age in
numbers."),
},
cancellationToken);
}
else
{
return await stepContext.NextAsync(-1, cancellationToken);
}
}
private async Task<DialogTurnResult>
ExecuteFinalConfirmStepAsync(WaterfallStepContext stepContext,
CancellationToken cancellationToken)
{
var userProfile = await
_accessors.UserProfile.GetAsync(stepContext.Context, () => new
UserProfile(), cancellationToken);
userProfile.Age = (int)stepContext.Result;
var message = GetAgeAcceptedMessage(userProfile);
await stepContext.Context.SendActivityAsync(message,
cancellationToken);
return await stepContext.PromptAsync(
"confirm",
new PromptOptions { Prompt = MessageFactory.Text("Is this
the registration information you want?") },
cancellationToken);
}
private static IActivity GetAgeAcceptedMessage(UserProfile
userProfile)
{
return MessageFactory.Text(userProfile.Age == -1 ? "Age is
private, isn't it?" : $"I'm {userProfile.Age} year old.");
}
private async Task<DialogTurnResult>
ExecuteSummaryStepAsync(WaterfallStepContext stepContext, CancellationToken
cancellationToken)
{
if ((bool)stepContext.Result)
{
var userProfile = await
_accessors.UserProfile.GetAsync(stepContext.Context, () => new
UserProfile(), cancellationToken);
var summaryMessages = GetSummaryMessages(userProfile);
await
stepContext.Context.SendActivitiesAsync(summaryMessages,
cancellationToken);
// End of Detail dialog
return await stepContext.EndDialogAsync(cancellationToken:
cancellationToken);
}
else
{
// Redo the Details dialog.
await
stepContext.Context.SendActivityAsync(MessageFactory.Text("I will visit you
again."), cancellationToken);
return await stepContext.ReplaceDialogAsync("details",
cancellationToken: cancellationToken);
}
}
private static IActivity[] GetSummaryMessages(UserProfile
userProfile)
{
IActivity summaryMessage = MessageFactory.Text(userProfile.Age
== -1
? $"{userProfile.HandleName} Your age is private."
: $"{userProfile.HandleName} , {userProfile.Age} year
old.");
IActivity thanksMessage = MessageFactory.Text("Thank you for
your input.");
return new[] { summaryMessage, thanksMessage };
}
//---------------------------
}
}
Chapter 5: Implementation Age Property
1. Go to UserProfile.cs , implement Age Property as shown below.
namespace HandsonBot.SampleBot
{
public class UserProfile
{
public string HandleName { get; set; }
public int Age { get; set; }
}
}
2. Debug your application again.
Happy Coding !!!

More Related Content

DOCX
Rhino Mocks
PDF
Chat application in java using swing and socket programming.
PDF
The Ring programming language version 1.3 book - Part 7 of 88
PPTX
Typescript barcelona
PPT
Swiss army knife Spring
PDF
Chat Room System using Java Swing
PPTX
Unit/Integration Testing using Spock
PDF
Testing logging in asp dot net core
Rhino Mocks
Chat application in java using swing and socket programming.
The Ring programming language version 1.3 book - Part 7 of 88
Typescript barcelona
Swiss army knife Spring
Chat Room System using Java Swing
Unit/Integration Testing using Spock
Testing logging in asp dot net core

What's hot (20)

PPTX
Legacy Code Kata v3.0
PPTX
Legacy Dependency Kata v2.0
PDF
JavaScript Refactoring
PDF
The Ring programming language version 1.5.4 book - Part 14 of 185
PPTX
Qunit Java script Un
PDF
Stop Making Excuses and Start Testing Your JavaScript
PDF
Auto-GWT : Better GWT Programming with Xtend
PPTX
Workflow Foundation 4
KEY
Gwt and Xtend
DOCX
Test Driven Development
PPT
Call Back
PPTX
2. Design patterns. part #2
ODP
From object oriented to functional domain modeling
PDF
DRYing to Monad in Java8
PPTX
PDF
Tomasz Polanski - Automated mobile testing 2016 - Testing: why, when, how
DOCX
Soaoui
PDF
The Ring programming language version 1.2 book - Part 5 of 84
PDF
Dive into SObjectizer 5.5. Introductory part
PPTX
Mockito intro
Legacy Code Kata v3.0
Legacy Dependency Kata v2.0
JavaScript Refactoring
The Ring programming language version 1.5.4 book - Part 14 of 185
Qunit Java script Un
Stop Making Excuses and Start Testing Your JavaScript
Auto-GWT : Better GWT Programming with Xtend
Workflow Foundation 4
Gwt and Xtend
Test Driven Development
Call Back
2. Design patterns. part #2
From object oriented to functional domain modeling
DRYing to Monad in Java8
Tomasz Polanski - Automated mobile testing 2016 - Testing: why, when, how
Soaoui
The Ring programming language version 1.2 book - Part 5 of 84
Dive into SObjectizer 5.5. Introductory part
Mockito intro
Ad

Similar to Bot builder v4 HOL (9)

PPTX
Building multi lingual and empatic bots - Sander van den Hoven - Codemotion A...
PDF
Bot-Tender: A Chat Bot Walks into a Bar (2020)
PDF
Bot & AI - A Bot for Productivity
PPTX
Build a mobile chatbot with Xamarin
PDF
Bot design AIsatPN 2018
PDF
Building chat bots using ai platforms (wit.ai or api.ai) in nodejs
PDF
Bots: Basics @ Javascript Tonight, 2017.09.22
PPTX
Chatbots - A CMD for Humans (Ort Braude 2018)
PPTX
Build intelligent chatbot with bot framework
Building multi lingual and empatic bots - Sander van den Hoven - Codemotion A...
Bot-Tender: A Chat Bot Walks into a Bar (2020)
Bot & AI - A Bot for Productivity
Build a mobile chatbot with Xamarin
Bot design AIsatPN 2018
Building chat bots using ai platforms (wit.ai or api.ai) in nodejs
Bots: Basics @ Javascript Tonight, 2017.09.22
Chatbots - A CMD for Humans (Ort Braude 2018)
Build intelligent chatbot with bot framework
Ad

More from Cheah Eng Soon (20)

PPTX
Microsoft Defender for Endpoint
PPTX
Azure Active Directory - Secure and Govern
PPTX
Microsoft Zero Trust
PPTX
MEM for OnPrem Environments
PPTX
Microsoft Threat Protection Automated Incident Response
PDF
Azure Penetration Testing
PDF
Azure Penetration Testing
PPTX
Microsoft Threat Protection Automated Incident Response Demo
PPTX
Microsoft Secure Score Demo
PPTX
Microsoft Cloud App Security Demo
PPTX
M365 Attack Simulation Demo
PPTX
Cloud Security Demo
PPTX
Azure Active Directory - External Identities Demo
PPTX
Azure WAF
PPTX
Azure Weekend 2020 Build Malaysia Bus Uncle Chatbot
PPTX
Microsoft Azure的20大常见安全漏洞与配置错误
PDF
20 common security vulnerabilities and misconfiguration in Azure
PPTX
Integrate Microsoft Graph with Azure Bot Services
PPTX
Azure Sentinel with Office 365
PPTX
3 Steps Integrate Microsoft Graph with Azure Bot Services
Microsoft Defender for Endpoint
Azure Active Directory - Secure and Govern
Microsoft Zero Trust
MEM for OnPrem Environments
Microsoft Threat Protection Automated Incident Response
Azure Penetration Testing
Azure Penetration Testing
Microsoft Threat Protection Automated Incident Response Demo
Microsoft Secure Score Demo
Microsoft Cloud App Security Demo
M365 Attack Simulation Demo
Cloud Security Demo
Azure Active Directory - External Identities Demo
Azure WAF
Azure Weekend 2020 Build Malaysia Bus Uncle Chatbot
Microsoft Azure的20大常见安全漏洞与配置错误
20 common security vulnerabilities and misconfiguration in Azure
Integrate Microsoft Graph with Azure Bot Services
Azure Sentinel with Office 365
3 Steps Integrate Microsoft Graph with Azure Bot Services

Recently uploaded (20)

PDF
A novel scalable deep ensemble learning framework for big data classification...
PPTX
Benefits of Physical activity for teenagers.pptx
PDF
Getting Started with Data Integration: FME Form 101
PDF
Developing a website for English-speaking practice to English as a foreign la...
PDF
From MVP to Full-Scale Product A Startup’s Software Journey.pdf
PDF
Taming the Chaos: How to Turn Unstructured Data into Decisions
PPTX
Web Crawler for Trend Tracking Gen Z Insights.pptx
PDF
Video forgery: An extensive analysis of inter-and intra-frame manipulation al...
PPTX
observCloud-Native Containerability and monitoring.pptx
PDF
STKI Israel Market Study 2025 version august
DOCX
search engine optimization ppt fir known well about this
PDF
Assigned Numbers - 2025 - Bluetooth® Document
PPT
What is a Computer? Input Devices /output devices
PPT
Module 1.ppt Iot fundamentals and Architecture
PDF
Univ-Connecticut-ChatGPT-Presentaion.pdf
PDF
Five Habits of High-Impact Board Members
PDF
1 - Historical Antecedents, Social Consideration.pdf
PDF
A contest of sentiment analysis: k-nearest neighbor versus neural network
PDF
DASA ADMISSION 2024_FirstRound_FirstRank_LastRank.pdf
PDF
Hindi spoken digit analysis for native and non-native speakers
A novel scalable deep ensemble learning framework for big data classification...
Benefits of Physical activity for teenagers.pptx
Getting Started with Data Integration: FME Form 101
Developing a website for English-speaking practice to English as a foreign la...
From MVP to Full-Scale Product A Startup’s Software Journey.pdf
Taming the Chaos: How to Turn Unstructured Data into Decisions
Web Crawler for Trend Tracking Gen Z Insights.pptx
Video forgery: An extensive analysis of inter-and intra-frame manipulation al...
observCloud-Native Containerability and monitoring.pptx
STKI Israel Market Study 2025 version august
search engine optimization ppt fir known well about this
Assigned Numbers - 2025 - Bluetooth® Document
What is a Computer? Input Devices /output devices
Module 1.ppt Iot fundamentals and Architecture
Univ-Connecticut-ChatGPT-Presentaion.pdf
Five Habits of High-Impact Board Members
1 - Historical Antecedents, Social Consideration.pdf
A contest of sentiment analysis: k-nearest neighbor versus neural network
DASA ADMISSION 2024_FirstRound_FirstRank_LastRank.pdf
Hindi spoken digit analysis for native and non-native speakers

Bot builder v4 HOL

  • 1. Bot Builder v4 HOL Chapter 1: Preparation • Visual Studio 2017 • .Net Core 2.x ( https://www.microsoft.com/net/download ) • Bot Builder V4 SDK Template for Visual Studio ( https://marketplace.visualstudio.com/items?itemName=BotBuilder.botb uilderv4 ) • Bot Emulator ( https://github.com/Microsoft/BotFramework- Emulator/releases ) • Ngrok (https://ngrok.com/ ) Or You can use Azure Bot Services . After Download the Ngrok, please launch your Bot Emulator and go to Emulator Settings and Setup as below.
  • 2. Chapter 2: Create Project 1. Launch your Visual Studio. 2. Create a New Project, File > New > Project 3. Select Multi-Project and Select Bot Builder Echo Bot v4 and Name your project, HandsonBot . Lastly , click OK button. 4. Make sure your bot template update to the v4.0.7
  • 3. 5. Test Run your project. Go to dropdownlist of IIS Express and Select HandsonBot , which is your project name and Press F5 for Debug your project. 6. After Debug, you will see the localhost as below. 7. Launch your Bot Framework Emulator and Click Open Bot and Select BotConfiguration.Bot that in your project.
  • 4. Chapter 3: Implementation of welcome message 1. Go to your project, right click > add new folder “SampleBot”. 2. After create the folder , right click > add class > name the class as “SampleBot”. 3. Implement the code as below. using Microsoft.Bot.Builder; using Microsoft.Bot.Builder.Dialogs; using Microsoft.Bot.Schema; using Microsoft.Extensions.Logging; using System; using System.Threading; using System.Threading.Tasks; namespace HandsonBot.SampleBot { public class SampleBot : IBot { private const string WelcomeText = "Welcome to Sample Bot"; private readonly ILogger _logger; private readonly SampleBotAccessors _accessors; // Added private readonly DialogSet _dialogs; // Added public SampleBot(SampleBotAccessors accessors, ILoggerFactory loggerFactory) // Updated { _accessors = accessors ?? throw new ArgumentException(nameof(accessors)); // Added _dialogs = new DialogSet(accessors.ConversationDialogState); // Added _dialogs.Add(new TextPrompt("name", ValidateHandleNameAsync)); _logger = loggerFactory.CreateLogger<SampleBot>(); _logger.LogInformation("Start SampleBot"); } private Task<bool> ValidateHandleNameAsync(PromptValidatorContext<string> promptContext, CancellationToken cancellationToken) { var result = promptContext.Recognized.Value; if (result != null && result.Length >= 3) { var upperValue = result.ToUpperInvariant(); promptContext.Recognized.Value = upperValue; return Task.FromResult(true); } return Task.FromResult(false); } public async Task OnTurnAsync(ITurnContext turnContext, CancellationToken cancellationToken = default(CancellationToken)) { if (turnContext.Activity.Type == ActivityTypes.Message) { // We will exchange normal messages here.
  • 5. await SendMessageActivityAsync(turnContext, cancellationToken); // updated } else if (turnContext.Activity.Type == ActivityTypes.ConversationUpdate) { await SendWelcomeMessageAsync(turnContext, cancellationToken); } else { _logger.LogInformation($"passed:{turnContext.Activity.Type}"); } await _accessors.ConversationState.SaveChangesAsync(turnContext, false, cancellationToken); await _accessors.UserState.SaveChangesAsync(turnContext, false, cancellationToken); } private static async Task SendWelcomeMessageAsync(ITurnContext turnContext, CancellationToken cancellationToken) { foreach (var member in turnContext.Activity.MembersAdded) { if (member.Id != turnContext.Activity.Recipient.Id) { await turnContext.SendActivityAsync(WelcomeText, cancellationToken: cancellationToken); } } } private async Task SendMessageActivityAsync(ITurnContext turnContext, CancellationToken cancellationToken) { var dialogContext = await _dialogs.CreateContextAsync(turnContext, cancellationToken); var dialogTurnResult = await dialogContext.ContinueDialogAsync(cancellationToken); var userProfile = await _accessors.UserProfile.GetAsync(turnContext, () => new UserProfile(), cancellationToken); // If the handle name is not registered in UserState if (userProfile.HandleName == null) { await GetHandleNameAsync(dialogContext, dialogTurnResult, userProfile, cancellationToken); } else { await turnContext.SendActivityAsync($"Hello {userProfile.HandleName}", cancellationToken: cancellationToken); } } private async Task GetHandleNameAsync(DialogContext dialogContext, DialogTurnResult dialogTurnResult, UserProfile userProfile, CancellationToken cancellationToken) { if (dialogTurnResult.Status is DialogTurnStatus.Empty) {
  • 6. await dialogContext.PromptAsync( "name", new PromptOptions { Prompt = MessageFactory.Text("Please tell me your handle name first."), RetryPrompt = MessageFactory.Text("The handle name must be at least 3 words long."), }, cancellationToken); } else if (dialogTurnResult.Status is DialogTurnStatus.Complete) { // Register your handle name with UserState userProfile.HandleName = (string)dialogTurnResult.Result; _logger.LogInformation($"Handle Name registration: {userProfile.HandleName}"); } } } } 4. Go to Startup.cs Change near line 57 From services.AddBot<EchoWithCounterBot>(options => to services.AddBot<SampleBot.SampleBot>(options => & Change near line 78 From ILogger logger = _loggerFactory.CreateLogger<EchoWithCounterBot>(); to ILogger logger = _loggerFactory.CreateLogger<SampleBot.SampleBot>();
  • 7. Chapter 4: State Management 1. Right Click “SampleBot” Folder > right click > Add > Create UserProfile.class and Implement the code as below. namespace HandsonBot.SampleBot { public class UserProfile { public string HandleName { get; set; } } } 2. Install the Microsoft.Bot.Builder.Dialogs Nuget Package. Go to Tools> Nuget Package Manager> Package Manager Console and type the command as below. Install-Package Microsoft.Bot.Builder.Dialogs 3. Implement of State management Accessor Right Click “SampleBot” Folder > right click > Add > Create SampleBotAccessors.class and Implement the code as below. using System; using Microsoft.Bot.Builder; using Microsoft.Bot.Builder.Dialogs; namespace HandsonBot.SampleBot { public class SampleBotAccessors { public IStatePropertyAccessor<DialogState> ConversationDialogState { get; set; } public IStatePropertyAccessor<UserProfile> UserProfile { get; set; } public ConversationState ConversationState { get; } public UserState UserState { get; } public SampleBotAccessors(ConversationState conversationState, UserState userState) { ConversationState = conversationState ?? throw new ArgumentNullException(nameof(conversationState)); UserState = userState ?? throw new ArgumentException(nameof(userState)); } } }
  • 8. 4. Change Startup.cs near line 111, to implement Application of UserState Class From var conversationState = new ConversationState(dataStore); options.State.Add(conversationState); To var conversationState = new ConversationState(dataStore); options.State.Add(conversationState); var userState = new UserState(dataStore); options.State.Add(userState); 5. Implement of SampleBotAccessors class in Startup.cs , add the following code as below. using System; using System.Linq; using HandsonBot.SampleBot; using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.Hosting; using Microsoft.Bot.Builder; using Microsoft.Bot.Builder.Dialogs; using Microsoft.Bot.Builder.Integration; using Microsoft.Bot.Builder.Integration.AspNet.Core; using Microsoft.Bot.Configuration; using Microsoft.Bot.Connector.Authentication; using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Logging; using Microsoft.Extensions.Options; namespace HandsonBot { /// <summary> /// The Startup class configures services and the request pipeline. /// </summary> public class Startup { private ILoggerFactory _loggerFactory; private bool _isProduction = false; public Startup(IHostingEnvironment env) { _isProduction = env.IsProduction(); var builder = new ConfigurationBuilder() .SetBasePath(env.ContentRootPath) .AddJsonFile("appsettings.json", optional: true, reloadOnChange: true) .AddJsonFile($"appsettings.{env.EnvironmentName}.json" , optional: true) .AddEnvironmentVariables();
  • 9. Configuration = builder.Build(); } /// <summary> /// Gets the configuration that represents a set of key/value application configuration properties. /// </summary> /// <value> /// The <see cref="IConfiguration"/> that represents a set of key/value application configuration properties. /// </value> public IConfiguration Configuration { get; } /// <summary> /// This method gets called by the runtime. Use this method to add services to the container. /// </summary> /// <param name="services">The <see cref="IServiceCollection"/> specifies the contract for a collection of service descriptors.</param> /// <seealso cref="IStatePropertyAccessor{T}"/> /// <seealso cref="https://docs.microsoft.com/en- us/aspnet/web-api/overview/advanced/dependency-injection"/> /// <seealso cref="https://docs.microsoft.com/en-us/azure/bot- service/bot-service-manage-channels?view=azure-bot-service-4.0"/> public void ConfigureServices(IServiceCollection services) { services.AddBot<SampleBot.SampleBot>(options => { var secretKey = Configuration.GetSection("botFileSecret")?.Value; var botFilePath = Configuration.GetSection("botFilePath")?.Value; // Loads .bot configuration file and adds a singleton that your Bot can access through dependency injection. var botConfig = BotConfiguration.Load(botFilePath ?? @".BotConfiguration.bot", secretKey); services.AddSingleton(sp => botConfig ?? throw new InvalidOperationException($"The .bot config file could not be loaded. ({botConfig})")); // Retrieve current endpoint. var environment = _isProduction ? "production" : "development"; var service = botConfig.Services.Where(s => s.Type == "endpoint" && s.Name == environment).FirstOrDefault(); if (!(service is EndpointService endpointService)) { throw new InvalidOperationException($"The .bot file does not contain an endpoint with name '{environment}'."); } options.CredentialProvider = new SimpleCredentialProvider(endpointService.AppId, endpointService.AppPassword); // Creates a logger for the application to use. ILogger logger = _loggerFactory.CreateLogger<SampleBot.SampleBot>();
  • 10. // Catches any errors that occur during a conversation turn and logs them. options.OnTurnError = async (context, exception) => { logger.LogError($"Exception caught : {exception}"); await context.SendActivityAsync("Sorry, it looks like something went wrong."); }; // The Memory Storage used here is for local bot debugging only. When the bot // is restarted, everything stored in memory will be gone. IStorage dataStore = new MemoryStorage(); // For production bots use the Azure Blob or // Azure CosmosDB storage providers. For the Azure // based storage providers, add the Microsoft.Bot.Builder.Azure // Nuget package to your solution. That package is found at: // https://www.nuget.org/packages/Microsoft.Bot.Builder.Azure/ // Uncomment the following lines to use Azure Blob Storage // //Storage configuration name or ID from the .bot file. // const string StorageConfigurationId = "<STORAGE- NAME-OR-ID-FROM-BOT-FILE>"; // var blobConfig = botConfig.FindServiceByNameOrId(StorageConfigurationId); // if (!(blobConfig is BlobStorageService blobStorageConfig)) // { // throw new InvalidOperationException($"The .bot file does not contain an blob storage with name '{StorageConfigurationId}'."); // } // // Default container name. // const string DefaultBotContainer = "<DEFAULT- CONTAINER>"; // var storageContainer = string.IsNullOrWhiteSpace(blobStorageConfig.Container) ? DefaultBotContainer : blobStorageConfig.Container; // IStorage dataStore = new Microsoft.Bot.Builder.Azure.AzureBlobStorage(blobStorageConfig.Connect ionString, storageContainer); // Create Conversation State object. // The Conversation State object is where we persist anything at the conversation-scope. var conversationState = new ConversationState(dataStore); options.State.Add(conversationState); var userState = new UserState(dataStore); options.State.Add(userState); });
  • 11. // Create and register state accesssors. // Acessors created here are passed into the IBot-derived class on every turn. services.AddSingleton<EchoBotAccessors>(sp => { var options = sp.GetRequiredService<IOptions<BotFrameworkOptions>>().Value; if (options == null) { throw new InvalidOperationException("BotFrameworkOptions must be configured prior to setting up the state accessors"); } var conversationState = options.State.OfType<ConversationState>().FirstOrDefault(); if (conversationState == null) { throw new InvalidOperationException("ConversationState must be defined and added before adding conversation-scoped state accessors."); } // Create the custom state accessor. // State accessors enable other components to read and write individual properties of state. var accessors = new EchoBotAccessors(conversationState) { CounterState = conversationState.CreateProperty<CounterState>(EchoBotAccessors.Counte rStateName), }; return accessors; }); // Create and register state accesssors. // Acessors created here are passed into the IBot-derived class on every turn. services.AddSingleton<SampleBotAccessors>(sp => { var options = sp.GetRequiredService<IOptions<BotFrameworkOptions>>().Value ?? throw new InvalidOperationException("BotFrameworkOptions must be configured prior to setting up the state accessors"); var conversationState = options.State.OfType<ConversationState>().FirstOrDefault() ?? throw new InvalidOperationException("ConversationState が ConfigureServices で設 定されていません。"); var userState = options.State.OfType<UserState>().FirstOrDefault()
  • 12. ?? throw new InvalidOperationException("UserState が ConfigureServices で設定されてい ません。"); var accessors = new SampleBotAccessors(conversationState, userState) { ConversationDialogState = conversationState.CreateProperty<DialogState>(nameof(DialogState)), UserProfile = userState.CreateProperty<UserProfile>(nameof(UserProfile)), }; return accessors; }); } public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory) { _loggerFactory = loggerFactory; app.UseDefaultFiles() .UseStaticFiles() .UseBotFramework(); } } } 6. Go back to SampleBot.cs added the following code with comment and Waterfallsteps. //Added: Part where code is added //Updated: Changing parts
  • 13. using Microsoft.Bot.Builder; using Microsoft.Bot.Builder.Dialogs; using Microsoft.Bot.Schema; using Microsoft.Extensions.Logging; using System; using System.Threading; using System.Threading.Tasks; namespace HandsonBot.SampleBot { public class SampleBot : IBot { private const string WelcomeText = "Welcome to Sample Bot"; private readonly ILogger _logger; private readonly SampleBotAccessors _accessors; // Added private readonly DialogSet _dialogs; // Added public SampleBot(SampleBotAccessors accessors, ILoggerFactory loggerFactory) { _accessors = accessors ?? throw new ArgumentException(nameof(accessors)); _dialogs = new DialogSet(accessors.ConversationDialogState); var waterfallSteps = new WaterfallStep[] { ConfirmAgeStepAsync, ExecuteAgeStepAsync, ExecuteFinalConfirmStepAsync, ExecuteSummaryStepAsync, }; _dialogs.Add(new TextPrompt("name", ValidateHandleNameAsync)); _dialogs.Add(new ConfirmPrompt("confirm")); _dialogs.Add(new NumberPrompt<int>("age")); _dialogs.Add(new WaterfallDialog("details", waterfallSteps)); _logger = loggerFactory.CreateLogger<SampleBot>(); _logger.LogInformation("Start SampleBot"); } private async Task GetHandleNameAsync(DialogContext dialogContext, DialogTurnResult dialogTurnResult, UserProfile userProfile, CancellationToken cancellationToken) { if (dialogTurnResult.Status is DialogTurnStatus.Empty) { await dialogContext.PromptAsync( "name", new PromptOptions { Prompt = MessageFactory.Text("Please tell me your handle name first."), RetryPrompt = MessageFactory.Text("The handle name must be at least 3 words long."), }, cancellationToken);
  • 14. } // If you enter a handle name else if (dialogTurnResult.Status is DialogTurnStatus.Complete) { if (dialogTurnResult.Result != null) { // Register your handle name with UserState userProfile.HandleName = (string)dialogTurnResult.Result; await dialogContext.BeginDialogAsync("details", null, cancellationToken); // added } } } private Task<bool> ValidateHandleNameAsync(PromptValidatorContext<string> promptContext, CancellationToken cancellationToken) { var result = promptContext.Recognized.Value; if (result != null && result.Length >= 3) { var upperValue = result.ToUpperInvariant(); promptContext.Recognized.Value = upperValue; return Task.FromResult(true); } return Task.FromResult(false); } public async Task OnTurnAsync(ITurnContext turnContext, CancellationToken cancellationToken = default(CancellationToken)) { if (turnContext.Activity.Type == ActivityTypes.Message) { // We will exchange normal messages here. await SendMessageActivityAsync(turnContext, cancellationToken); // updated } else if (turnContext.Activity.Type == ActivityTypes.ConversationUpdate) { await SendWelcomeMessageAsync(turnContext, cancellationToken); } else { _logger.LogInformation($"passed:{turnContext.Activity.Type}"); } await _accessors.ConversationState.SaveChangesAsync(turnContext, false, cancellationToken); await _accessors.UserState.SaveChangesAsync(turnContext, false, cancellationToken); }
  • 15. private static async Task SendWelcomeMessageAsync(ITurnContext turnContext, CancellationToken cancellationToken) { foreach (var member in turnContext.Activity.MembersAdded) { if (member.Id != turnContext.Activity.Recipient.Id) { await turnContext.SendActivityAsync(WelcomeText, cancellationToken: cancellationToken); } } } public async Task SendMessageActivityAsync(ITurnContext turnContext, CancellationToken cancellationToken) { var dialogContext = await _dialogs.CreateContextAsync(turnContext, cancellationToken); var dialogTurnResult = await dialogContext.ContinueDialogAsync(cancellationToken); var userProfile = await _accessors.UserProfile.GetAsync(turnContext, () => new UserProfile(), cancellationToken); // If the handle name is not registered in UserState if (userProfile.HandleName == null) { await GetHandleNameAsync(dialogContext, dialogTurnResult, userProfile, cancellationToken); } // If you have a handle name registered with UserState else { // added if (dialogTurnResult.Status == DialogTurnStatus.Empty) { await dialogContext.BeginDialogAsync("details", null, cancellationToken); } } } //---------------------------------------------- //Lab private async Task<DialogTurnResult> ConfirmAgeStepAsync(WaterfallStepContext stepContext, CancellationToken cancellationToken) { var userProfile = await _accessors.UserProfile.GetAsync(stepContext.Context, () => new UserProfile(), cancellationToken); return await stepContext.PromptAsync( "confirm", new PromptOptions { Prompt = MessageFactory.Text($"{userProfile.HandleName} May I ask your age?"),
  • 16. RetryPrompt = MessageFactory.Text("Answer yes or No."), }, cancellationToken); } private async Task<DialogTurnResult> ExecuteAgeStepAsync(WaterfallStepContext stepContext, CancellationToken cancellationToken) { if ((bool)stepContext.Result) { return await stepContext.PromptAsync( "age", new PromptOptions { Prompt = MessageFactory.Text("What is your age?"), RetryPrompt = MessageFactory.Text("Enter the age in numbers."), }, cancellationToken); } else { return await stepContext.NextAsync(-1, cancellationToken); } } private async Task<DialogTurnResult> ExecuteFinalConfirmStepAsync(WaterfallStepContext stepContext, CancellationToken cancellationToken) { var userProfile = await _accessors.UserProfile.GetAsync(stepContext.Context, () => new UserProfile(), cancellationToken); userProfile.Age = (int)stepContext.Result; var message = GetAgeAcceptedMessage(userProfile); await stepContext.Context.SendActivityAsync(message, cancellationToken); return await stepContext.PromptAsync( "confirm", new PromptOptions { Prompt = MessageFactory.Text("Is this the registration information you want?") }, cancellationToken); } private static IActivity GetAgeAcceptedMessage(UserProfile userProfile) { return MessageFactory.Text(userProfile.Age == -1 ? "Age is private, isn't it?" : $"I'm {userProfile.Age} year old."); } private async Task<DialogTurnResult> ExecuteSummaryStepAsync(WaterfallStepContext stepContext, CancellationToken cancellationToken) { if ((bool)stepContext.Result) {
  • 17. var userProfile = await _accessors.UserProfile.GetAsync(stepContext.Context, () => new UserProfile(), cancellationToken); var summaryMessages = GetSummaryMessages(userProfile); await stepContext.Context.SendActivitiesAsync(summaryMessages, cancellationToken); // End of Detail dialog return await stepContext.EndDialogAsync(cancellationToken: cancellationToken); } else { // Redo the Details dialog. await stepContext.Context.SendActivityAsync(MessageFactory.Text("I will visit you again."), cancellationToken); return await stepContext.ReplaceDialogAsync("details", cancellationToken: cancellationToken); } } private static IActivity[] GetSummaryMessages(UserProfile userProfile) { IActivity summaryMessage = MessageFactory.Text(userProfile.Age == -1 ? $"{userProfile.HandleName} Your age is private." : $"{userProfile.HandleName} , {userProfile.Age} year old."); IActivity thanksMessage = MessageFactory.Text("Thank you for your input."); return new[] { summaryMessage, thanksMessage }; } //--------------------------- } }
  • 18. Chapter 5: Implementation Age Property 1. Go to UserProfile.cs , implement Age Property as shown below. namespace HandsonBot.SampleBot { public class UserProfile { public string HandleName { get; set; } public int Age { get; set; } } } 2. Debug your application again. Happy Coding !!!