This is the first in a six-post series, where we explore the Bot Builder C# SDK v4:
- How does a Bot Builder v4 bot work? (this article)
- How to send proactive messages with Bot Builder v4?
- How to receive events in a Bot Framework SDK v4 Web API bot?
- How to test a Bot Framework SDK v4 bot?
- How to do integration testing for a Bot Framework SDK v4 event bot?
- How to build a Bot Framework SDK v4 bot as an Azure Function web API app?
In this post we explore the core fundamentals of the messages flow inside a bot developed with Bot Builder C# SDK v4.
The new v4 paradigm arguably makes it easier to create a bot than v3, but the introduced change might represent an important barrier if you’re coming from v3.
One significant change is the departure from the familiar Web API paradigm, however, as we’ll see in this article, that apparent departure is not really that large and you can actually still use a Web API approach.
The Bot Builder C# SDK is built on top of ASP.NET Core so we’ll develop a simple bot as a Web API app, and by going this way we’ll realize it’s actually quite simple.
So let’s get into the details.
WARNING: The code shown here is experimental and has not been tested in production, so handle with care!
The following diagram shows a simplified flow of messages during an interaction with a bot.
And these are the most important steps:
When users types some text in their device, it’s sent through a channel to the Azure Bot Service.
The Azure Bot Service creates an
Activityand sends a post request to your ASP.NET Core bot application.
The request enters the “request pipeline” where several Middleware components are registered and one of them is the
BotMessageHandler, that “intercepts” requests to
/api/messagesto handle them. The
MvcRoutHandleris another middleware that can be registered in the request pipeline with the
app.UseMvc()method in the
BotMessageHandlerrequests instances of the
IBotto Dependency Injection and calls the
BotFrameworkAdapterto process the
TurnContextand calls the bot handler method (
OnTurnAsync) to process the
While processing the activity, the bot can send back as many activities as needed to the Bot Service, through the adapter. Each one of this activities is a request to a channel’s
ServiceUrlin the Bot Service.
The user can see each activity message immediately.
It’s important to highlight that the adapter can send a message through the Bot Service at any time, as long as it knows the channel’s
ServiceUrl and the conversation that must receive the message.
The following diagram shows the general approach we’ll use in this article:
Instead of the Bot Framework’s
BotFrameworkAdapter we’ll use a simple “activity action”, in a regular MVC controller, to receive the POST request from the Bot Service and then do the equivalent of step 4 in the above to process, as shown in the next diagram.
So, with this knowledge in hand, we’ll now implement what’s probably the simplest Web API bot you can make.
This will be a plain EchoBot, similar to the published v4 sample, but implemented as a Web API app.
So, to begin with, you create an ASP.NET Core Web API app, without any authentication or https. Then make a few changes outlined here:
- Drop the initial controller (
- Create a
BotControllerthat will be our controller-based bot.
- Create a home Razor page as the home (
- Register an adapter factory while configuring the DI container in
Program.csto add logging with Serilog + Seq, to make it easier to explore the inner workings of our bot.
In the following sections we’ll review the details of the important code here, you can explore the rest in the GAB2019-BotInternals GitHub repo.
This the code for the simplest api controller that’s able to process messages from the Bot Service (or the Bot Emulator):
In the code above:
Request the adapter type, an
IAdapterIntegration, from Dependency Injection (DI) (line 9).
Receive the activity from the request body (line 16).
Send the activity to the adapter’s
ProcessActivityAsyncmethod (line 20), passing the method
OnTurnAsync, that’s defined right there in the controller, as the handler of the activity (line 23). You may recognize this method just like the core method in any bot, and you can name it whatever you like.
Get the text sent by the user (line 27).
Send it back through the
TurnContext.SendActivitymethod (line 32).
It’s important to highlight here that, if you wanted to use a regular v4
IBot here, you’d only have to inject the bot and pass its
OnTurnAsync method to the
ProcessActivityAsync method like so:
return await _adapter.ProcessActivityAsync(string.Empty, activity, _bot.OnTurnAsync, default);
And then delete lines 23-38, as we’ll see that in the next article.
To try out your simple bot, you also have to register the required types in the DI container, in
Startup.cs, as shown next.
Register a BotFrameworkAdapter factory in the DI container
This is also the simplest possible adapter, without any type of authentication or adapter middleware, so it’s only usable with the Bot Emulator.
In the code above:
BotFrameworkAdapteris registered as a singleton (line 5).
SimpleCredentialProviderdoesn’t need username or password (line 10), because we’ll be using the Bot Emulator.
Setting up logging with Serilog + Seq
Now we’ll add logging, as a good practice in general, and also as a nice way to explore the processes and variables.
Serilog is an open source project in GitHub and even though Seq is not, it’s possible to use it for free for development and small projects.
To use Serilog you just have to install a few packages that you can see in
To use Seq you have two options to install the product:
Locally in your development machine
In a Docker container
If you can assign 2 GB to Docker, I recommend the second option. In this case you just need to:
Install Docker with the default configuration (using Linux containers) and
Create the following batch file to install and run Seq with Docker in a single operation:
docker start seq if errorlevel 1 docker run --name seq -d -e ACCEPT_EULA=Y -p 5341:80 datalust/seq:latest rem wait for 5 seconds ping -n 5 127.0.0.1 > nul start http://localhost:5341/#/events?deletionEnabled
You can get the details to install Seq locally in Seq’s documentation site.
Explore the logs
Once you change
Program.cs to the code in the repo, you should be able to use Seq to view the bot’s events, and it should look similar to the following:
And this is an excellent tool to explore in detail the internals of your applications.
The code in
Startup.cs in the repo, also registers a
SerilogMiddleware, that logs directly from the ASP.NET Core pipeline, that also gives you some additional insights.
Test with the Bot Emulator
Now you’re ready to test the bot and you just have to:
Run your Web API app with [Ctrl+F5] or [F5] to inspect with the debugger and
Open the file
SimpleWebApiBot.botwith the Bot Emulator and send a message to your bot.
To summarize, in this post we’ve learned:
- The core working principles of the Bot Builder v4.
- To use a standard Web API controller to implement a bot, using only the BotFrameworkAdapter from the Bot Builder v4.
- To set up and use logging with Serilog and Seq.
I Hope you’ve found this post interesting and useful. Follow me on Twitter for more posts.
You are also welcomed to leave a comment or ask a question in the comments section below.
Code repository in GitHub
Bot Builder v4 samples
Seq development and small projects licensing
Structured Logging blog post