Introduction
In my previous
article, we tried to understand the basics of the Microsoft Bot Framework. Now, in this article, we will develop a basic Echo Bot for you guys to understand how to set up a hello world application. Next, we will implement a greeting bot that will greet us and will ask for our name, and then we will see that it will be able to remember our name with the help of our user ID. As of now, we will use Microsoft bot Builder's MemoryStorage, which is a storage layer that uses an in-memory dictionary. I will also place the code for you guys to use AzureBlobStorage attaching your storage account and storage container name if you guys wish to use Azure services and it will enable our Bot to always remember your user ID.
So, without wasting more time, let's dive into it. Below are the following prerequisites that we should have on our system:
Understand What We Have in the Echo Bot Template
After installing the prerequisites, open your Visual Studio and select the Project Extension, just like below:
It will ask you to give the project name and browse the location for the projects, etc. You can fill them and refer to the below screen.
Click on Create. You should be able to see the below solutions with folders:
You will find this project structure similar to .NET core projects, where you have a www-root folder and have a Startup.cs class file as well. You might be wondering why, but since bot applications are a web application, and when we use the VSIX template, then it generates an ASP.NET MVC Core application, and these files are similar to the core app, which is required for all web apps and are not bot specific.
The appsettings.json is the configuration file that contains information specific to your bot such as app ID, passwords, etc. You can later add on your keys or URL to this configuration file according to your environment. But for this example, its empty which is quite normal and because right now we don’t need it.
As I have already told you, a bot is a web application. Here, because we are using an ASP.NET MVC core application, the folder you will see controllers and bots are only related to that. We will talk more about the classes which these folders have but you can keep in mind that it is the same as MVC core web application.
Bots folder contains one class EchoBot which extends ActivityHandler which implements the IBot interface. For now, you will notice that we have two methods which already override for us. OnMessageActivityAsync is used when your bot receives a message activity. Whenever the turn handler sees any incoming activity, then it will send it to the OnMessageActivityAsync activity handler. So, we will use this method for handling and responding to message with our own logic while building our bot.
Another method which is OnMemeberAddedAsync handler will be used the same as OnMessageActivityAsync but rather than the message we will be handling members.
These two methods are for you to implement your own logic for building your bot specific to your needs. There will be times when you want to override base turn handler for maybe saving states and all. So, you have to make sure that you are calling await base.OnTurnAsyn(turnContext, cancellationToken); first, just to make sure base implementation is run before your additional logic.
turnContext provides information about an incoming activity, which corresponds to the inbound HTTP request. You will find strongly typed activity in handler turn context.
In this sample, you will see that we will just welcome a new user or echo back the message the user sent using the SendActivityAsync call.
- public class EchoBot : ActivityHandler
- {
- protected override async Task OnMessageActivityAsync(ITurnContext<IMessageActivity> turnContext, CancellationToken cancellationToken)
- {
- var replyText = $"Echo: {turnContext.Activity.Text}";
- await turnContext.SendActivityAsync(MessageFactory.Text(replyText, replyText), cancellationToken);
- }
-
- protected override async Task OnMembersAddedAsync(IList<ChannelAccount> membersAdded, ITurnContext<IConversationUpdateActivity> turnContext, CancellationToken cancellationToken)
- {
- string welcomeText = "Hello and welcome!";
- foreach (var member in membersAdded)
- {
- if (member.Id != turnContext.Activity.Recipient.Id)
- {
- await turnContext.SendActivityAsync(MessageFactory.Text(welcomeText, welcomeText), cancellationToken);
- }
- }
- }
- }
Run Your First Bot
In order to run your bot for the first time, we first need to start our bot emulator which we have downloaded earlier. Once it’s up and running you should be able to see the below screen.
Now just rebuild your solution on Visual Studio and run it using the below configuration:
Select EchoBot profile and run it. You will see events on command prompt just like below:
You will observe that your bot has now started on https://localhost:3979/ and you will see the below screen. If it asks for an https certificate, then you can always release the certificate for your localhost.
You must pay attention to the above-highlighted URL, which is your bot’s endpoints. You will use this URL to connect to your bot on bot emulator. So, copy this URL and paste it on Emulator just like below.
Click on connect and you should be able to see the below screen:
You can type your message to see if that Echo is back again to us or not. Just like shown below:
You will notice on the right-hand side of the emulator your request is logged as well and displayed to you so you know which request is getting processed.
So, you have now successfully created your EchoBot. You will see our bot just said, “Hello and welcome!”. In the next segment, we will debug our code.
Debug your Code
So, to debug your code, put the debugger point at the below line in the EchoBot class:
Now, on your bot emulator click on "restart the conversation - New User Id. As soon as you click on this your debugger, it will hit the OnMemberAddedAsync method and you will see as we are setting the welcome text and sending this activity to our users. just press f5 and see you will receive the welcome message on your Bot Emulator.
Develop a Greeting Bot that Remembers Your Name
Until now, we were just using the template version of our EchoBot which comes with the template which we installed at the starting of this article. Now, we will extend the functionality of our bot to remember our name and store it in the in-memory dictionary. You can follow this blog up or you can just clone my repository from GitHub, below is the URL:
So let's start. First, we will create our new Greeting Bot. So, go ahead and create the GreetingBot class in Bots folder and paste the below code for this class.
- public class GreetingBot : ActivityHandler
- {
- #region Variables
- private readonly BotStateService _botStateService;
- #endregion
-
- public GreetingBot(BotStateService botStateService)
- {
- _botStateService = botStateService ?? throw new System.ArgumentNullException(nameof(botStateService));
- }
- protected override async Task OnMessageActivityAsync(ITurnContext<IMessageActivity> turnContext, CancellationToken cancellationToken)
- {
- await GetName(turnContext, cancellationToken);
- }
-
- protected override async Task OnMembersAddedAsync(IList<ChannelAccount> membersAdded, ITurnContext<IConversationUpdateActivity> turnContext, CancellationToken cancellationToken)
- {
- foreach (var member in membersAdded)
- {
- if (member.Id != turnContext.Activity.Recipient.Id)
- {
- await GetName(turnContext, cancellationToken);
- }
- }
- }
-
- private async Task GetName(ITurnContext turnContext, CancellationToken cancellationToken)
- {
- UserProfile userProfile = await _botStateService.UserProfileAccessor.GetAsync(turnContext, () => new UserProfile());
- ConverstationData converstationData = await _botStateService.ConversationDataAccessor.GetAsync(turnContext, () => new ConverstationData());
- if (!string.IsNullOrEmpty(userProfile.Name))
- {
- await turnContext.SendActivityAsync(MessageFactory.Text(String.Format("Hi {0}. How can I help you today?", userProfile.Name)), cancellationToken);
- }
- else
- {
- if (converstationData.PromptedUserForName)
- {
-
- userProfile.Name = turnContext.Activity.Text?.Trim();
-
-
- await turnContext.SendActivityAsync(MessageFactory.Text(String.Format("Thanks {0}. How can I help you today?", userProfile.Name)), cancellationToken);
-
-
- converstationData.PromptedUserForName = false;
- }
- else
- {
-
- await turnContext.SendActivityAsync(MessageFactory.Text("Hi GoodMorning!! I am MPBot."), cancellationToken);
-
-
- await turnContext.SendActivityAsync(MessageFactory.Text("What is your name?"), cancellationToken);
-
-
- converstationData.PromptedUserForName = true;
- }
-
-
- await _botStateService.UserProfileAccessor.SetAsync(turnContext, userProfile);
- await _botStateService.ConversationDataAccessor.SetAsync(turnContext, converstationData);
-
- await _botStateService.UserState.SaveChangesAsync(turnContext);
- await _botStateService.ConversationState.SaveChangesAsync(turnContext);
-
- }
- }
- }
We need our models, so create below two model classes as well: ConversationData.cs and Userprofile.cs
- public class ConverstationData
- {
-
- public bool PromptedUserForName { get; set; } = false;
- }
- public class UserProfile
- {
- public string Name { get; set; }
- }
We need one state service to initialize the conversation state accessors and the user state. So, go ahead create one service class called BotStateService.cs and paste the below code:
- public class BotStateService
- {
- #region Variables
-
- public ConversationState ConversationState { get; }
- public UserState UserState { get; }
-
-
- public static string UserProfileId { get; } = $"{nameof(BotStateService)}.UserProfile";
- public static string ConverstationDataId { get; } = $"{nameof(BotStateService)}.ConversationData";
-
-
- public IStatePropertyAccessor<UserProfile> UserProfileAccessor { get; set; }
- public IStatePropertyAccessor<ConverstationData> ConversationDataAccessor { get; set; }
- #endregion
-
- public BotStateService(ConversationState conversationState, UserState userState)
- {
- ConversationState = conversationState ?? throw new ArgumentNullException(nameof(ConversationState));
- UserState = userState ?? throw new ArgumentNullException(nameof(userState));
-
- InitializeAccessors();
- }
-
- private void InitializeAccessors()
- {
-
- ConversationDataAccessor = ConversationState.CreateProperty<ConverstationData>(ConverstationDataId);
-
-
- UserProfileAccessor = UserState.CreateProperty<UserProfile>(UserProfileId);
- }
- }
We are almost done. Now, we have to change the logic of our startup class to make sure we are running our greeting bot with our configurations. Change your startup class just like shown in the below code:
- public class Startup
- {
- public Startup(IConfiguration configuration)
- {
- Configuration = configuration;
- }
-
- public IConfiguration Configuration { get; }
-
-
- public void ConfigureServices(IServiceCollection services)
- {
- services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_1);
-
-
- services.AddSingleton<IBotFrameworkHttpAdapter, AdapterWithErrorHandler>();
-
-
- ConfigureState(services);
-
-
- services.AddTransient<IBot, GreetingBot>();
- }
-
- public void ConfigureState(IServiceCollection services)
- {
-
- services.AddSingleton<IStorage, MemoryStorage>();
-
-
-
-
-
-
-
- services.AddSingleton<UserState>();
-
-
- services.AddSingleton<ConversationState>();
-
-
- services.AddSingleton<BotStateService>();
- }
-
-
- public void Configure(IApplicationBuilder app, IHostingEnvironment env)
- {
- if (env.IsDevelopment())
- {
- app.UseDeveloperExceptionPage();
- }
- else
- {
- app.UseHsts();
- }
-
- app.UseDefaultFiles();
- app.UseStaticFiles();
- app.UseWebSockets();
-
- app.UseMvc();
- }
- }
As I told you earlier, you can use Azure service as well for storage and I have commented out that code which you can use for your account. You have to provide your Account Name, Key and Container Name and instead of using MemoryStorage you can use AzureBlobStorage. All you need is to set up these in your Azure Account.
One more thing I wanted to talk about is that you also have one file MpTeams Bot.bot in your solution which contains the configuration of your Bot just like in my case I have below configurations.
- {
- "name": "MpTeams Bot",
- "description": "",
- "services": [
- {
- "type": "endpoint",
- "appId": "",
- "appPassword": "",
- "endpoint": "http://localhost:3978/api/messages",
- "id": "853a8e50-7e42-11ea-9ea2-5b5aa38ed7d7",
- "name": "Development"
- }
- ],
- "padlock": "",
- "version": "2.0",
- "overrides": null,
- "path": "C:\\Users\\ba35925\\Desktop\\MSTeamsBot\\MPTeams\\MpTeams Bot.bot"
- }
So, we are all set now lets run our Greeting Bot and see the changes. Once you connect your bot to your emulator, you should be able to see the below message:
As you can see that our bot first greeted us and then asked for our name to store in its memory. Now as we have provided our name now let's see if it can remember our name next time when we start our conversation with our same userId. Now, select the below option on your emulator and check that our bot remembers our name or not.
You will see below message that our bot remembers our name and greet us:
Awesome!!! So this is how you can use your bot to remember your names and many more things just like this one. I hope you enjoyed this tutorial. let me know for anything you want to know. I will try to help you out.