If you are not familiar with the command pattern, click here to read about it.
In this article we’ll show you how you can implement the
Command Pattern using scorables, which will allow you to create an easily scalable architecture such that you can seamlessly add new features (commands) to your Bot in the future.
What are Scorables?
Within the Bot Framework .NET SDK,
Scorables allows you to create dialogs as flexible components in lieu of the traditional model.
If you’ve built a Bot using the Microsoft Bot Framework before, you likely have some familiarity with the dialog stack. In the example below, let’s say a user was in the
GetWeather Dialog but decided they wanted to switch to the
RealEstate Dialog. Under traditional dialog flow, a user would need to navigate through the following dialogues (
OtherDialog, potentially more), then resolve each dialog on the stack all the way to the
RootDialog before being able to access the
RealEstate Dialog that the user wanted.
Scorable dialogs within a bot monitor all incoming messages, and determine whether or not that message is actionable in some way. Messages that are scorable are then given a score between 0-1 (1 being the highest) by each Scorable dialog within the bot, the scorable dialogue which determines the highest score then handles the response to the user. When a user triggers a Scorable Dialog, that dialog will now be added to the top of the existing dialog stack, and upon resolution the conversation can continue from where it left off.
With scorables, we can build dialogs for a bot as a reusable component rather than dealing with the old strict dialogue structure to create more flexible conversations, and handle some common things a user might want to do.
Creating a Scorable dialog
In order to create a scorable dialogue, you’ll need to implement the
IScorable interface, which defines several methods you must implement:
PrepareAsync: This first method in the scorable instance accepts incoming message activity, analyzes it and sets the dialog’s
state, which is passed to all the other methods in the interface.
HasScore: This boolean method checks the state property to determine if the Scorable Dialog should provide a score for the message. If it returns false, the message will be ignored by the Scorable dialog.
GetScore: Will only trigger if
HasScorereturns true, provision the logic here to determine the score for a message between 0 - 1.0
PostAsync: This method is called if the scorable “wins” (observes the highest score between all the Scorable dialogs), in here core actions are performed.
DoneAsync: Here you should dispose of any scoped resources as it is called when the scoring process has completed.
As stated above, the
state instance produced in the
PrepareAsync method is passed to all the other methods in the interface. Each method will use this
state to implement its’ logic.
HasScore will return a true/false if the message includes a state that identifies it as scorable. Assuming
HasScore returns true, the
GetScore method will be called to compare this scorable among other possible instances, and compare each instance’s assigned score from 0-1. Finally, the
PostAsync method will be triggered by whichever scorable dialogue observes the highest score among those instances.
Now that we’ve explained what Scorables are, we’ll focus on how to leverage them to create a command pattern architecture for bots.
Creating a command IScorable
Back to setting up a command pattern for a bot, we can implement this by creating an abstract base class (which uses the
IScorable<IActivity, double> interface) for your commands to inherit. Custom logic can then be defined in each individual command which inherits from this abstract class.
We can define this abstract base class like this:
PrepareAsync method receives the user’s message to the bot and checks whether the message contains a specific
Command property value. The
Command property in this class defines what user input the command instance will respond to. If the message does contain
the corresponding command, this base command returns true. Finally, the
PostAsync operation from the
IScorable interface will run in order to provide an answer to the user by using the protected
With this abstract class set up to handle the Scorable interface for our commands, let’s go over an example command using this new abstract class. Suppose you wanted to define a command which reacts to a user asking for
How does this relate to the command pattern? The four key concepts of the command pattern are command, receiver, invoker, and client.
- Command: Represented by each non-abstract scorable class in the solution having the
- Receiver: On each command itself, represented by the logic performed at the
PostAsyncmethod overriden from the base command class.
- Invoker: The bot builder framework’s scorable evaluation logic processes a set of scorable instances, evaluates them in order to get highest scoring one, and if there is any, dispatches it.
- Client: The bot itself levering the bot builder SDK, the bot has access to registered IScorable types, the order to instance them, and provides those instances to the scorable evaluation logic in order to dispatch the best result (which would be the
Registering your Commands
You now need to register your commands within the bot builder framework message handling pipeline. If you’ve created your own bots in the past, this operation may seem familiar.
To register the commands you want your bot to handle, while interacting with the user, you could simply update the
as shown below within your app initialization at global.asax:
Once done, you can run your bot and if the user submits a message like:
Help me open an account
HelpCommand will intercept it and execute the logic you implemented at its
method in order to provide an appropriate answer.
You should still maintain a
root dialog in case none of a user’s messages correspond to a command. You should instance it from the WebAPI controller method that usually handles /api/messages as shown below:
Note: If you implement the
IScorable<IActivity, double>, then you can register those types within the Conversation.Container in orderto score the IActivity received during the handling pipeline.
A More complex scenario
Many channels provide the ability to attach interactive elements such as cards. The Bot Framework supports
Hero Card, Thumbnail Card, Receipt Card, Sign-In Card, Animation Card, Video and Audio Cards, and the recently introduced Adaptive Cards.
Once a card type has been built, it is mapped into an
Attachment data structure to be returned to as a reply the user.
Perhaps your bot needs to showcase more than one of these card attachments. Each one of the afforementioned cards is generated in a specific way,
but those results are being sent as attachments. Instead of building multiple handlers for each card scenario, we could create a shared abstract
core which attaches the card to the reply back to the user (in the
PostAsync method), providing an overridable method for custom descendents to generate card contents.
We’ll create a
RichCardSCorable class as shown below. The
message.Attachments property of the message activity is assigned with a new list of card attachments containing the attachment
How would the command actually build and return a card? Let’s examine the
Sign-In card as an example below. The descendant class implements the
Command and the
GetCardAttachment method that remained abstract:
In this article we described what scorables are, and shown how you can leverage them to implement a command pattern-like architecture within your bots. To see a detailed bot sample where all these benefits are showcased, see the Test Bot live sample.
You can also check out the following links for more information about Scorables in the .NET SDK:
Pablo Constantini, Ezequiel Jadib and Matthew Shim from the Bot Framework Team