Echo Bot deconstructed

This post has sat in draft for a year, hopefully it’s still relevent…

I’ve returned to doing some stuff using the Microsoft Bot Framework and updated everything to SDK 4 and some things have changed. I’m not going to waste time look at the changes so much as looking at the EchoBot template which comes with the latest SDK.

Getting started

If you haven’t already got it, you’ll need to install the Bot Builder V4 SDK Template for Visual Studio.

Note: If you instead decide to first go to Azure and create a Bot sample, the code for the EchoBot is (at the time of writing) very different to the template’s code.

Now if you create a new project in Visual Studio using this template you’ll end up a simple Bot that you can immediately run. Next, using the new Bot Framework Emulator (V4) select Open Bot from the emulator’s Welcome screen, then locate the .Bot file that came with the EchoBot and open this (or if you prefer put the Url http://localhost:3978/api/messages into the dialog). Then the Bot will be started and within a short amount of type you should see the following text

conversationUpdate event detected

Note: you will see the text twice, don’t worry about that, it’s normal at this point.

Now typing something into the emulator and press enter and you’ll be presented with something like the following

Turn 1: You sent ‘hi’

As you can see, I typed “Hi” and the Bot echoes it back.

At this point we’ve a working Bot.

Navigating the code

Program.cs

The Program.cs file contains the (as you’d expect) main start-up code for Kestrel to run etc. It configures logging and then bootstraps the Startup class. By default UseApplicationInsights() is commented out but obviously this is very useful once we deploy to Azure, for now leave it commented out. We can also enable logging to the Console etc., see Logging in ASP.NET Core for further information on options here.

Startup.cs

Startup is used to configure services etc. It’s the place we’ll add code for dependency injection etc. The first thing we’ll see within the constructor is the following

_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();

_isProduction is set to development when running on your local machine and to production by default, when run from Azure. The rest of the code creates a combined set of configuration, using the supplied appsettings.json file (part of the template’s project) along with any appsettings.json file for the specified environment. Meaning when running in development we might have differing configuration values from the production environment.

The next interesting method is ConfigureServices, where, as you’ll have guessed, we set-up any dependencies prior to their uses within the Bot code etc. The template code also expects the .bot file to exist. This file acts as further configuration and is not a requirement for a Bot to work, you could easily remove the .bot file and move configuration to the appsettings.json and (as stated previously) use the URL instead within the emulator (instead of the .bot file) and in fact. according to Manage bot resources the Bot file is being deprecated in favour of appsettings.json or .env file. However, for now it’s still part of the template, so I’m not going to cover the Bot file much further here, suffice to say it’s configuration is added to the dependency container in case you need access to it.

Jumping over where we located the endpoint from the .bot file, next up, a data store is created. This one is a MemoryStorage object and it’s primarily for local/debug builds in that it’ll lose its state upon a Bot restart. For production environments where we need to store such state we’ve use something like AzureBlobStorage , CosmoDB or any other cloud based persistence storage.

The ConversationState is then created and will be stored within the previously create IStorage, i.e. the MemoryStorage in this example. Conversation state is basically the state from the conversation taking place between user and Bot. This obviously becomes very useful in less trivial examples where dialogs are involved. In the echo Bot example it tracks the conversation counter state.

Finally within the ConfigureServices method we add our Bot to the container setting up any credentials as well as setting up a catch-all error handler.

The last method within the Startup.cs sets up the ability for the web app to display default and static files as well setting up endpoints etc. for the Bot framework.

EchoBotSampleAccessors.cs

The accessors file will be named after your project name and is basically a wrapper around the conversation state, see Create state property accessors. In the case of the Echo template it wraps the counter state and conversation state.

wwwroot/default.htm

By default, when you run the Bot an HTML page is displayed.

EchoBotBot.cs

Depending on your project name you’ll have a class which implements IBot. The key method of an IBot is the OnTurnAsync method, this is similar to an event look in Windows, it’s basically called upon each turn of a conversation.