Event-driven conversations using an activity handler

APPLIES TO: SDK v4

An activity handler is an event-driven way to organize the conversational logic for your bot. Each different type or sub-type of activity represents a different type of conversational event. Under the covers, the bot's turn handler calls the individual activity handler for whatever type of activity it received.

For example, if the bot receives a message activity, the turn handler would see that incoming activity and send it to the on message activity activity handler. When building your bot, your bot logic for handling and responding to messages will go in this on message activity handler. Likewise, your logic for handling members being added to the conversation will go in your on members added handler, which is called whenever a member is added to the conversation.

For other ways to organize your bot logic, see the bot logic section in how bots work.

To implement your logic for these handlers, you will override these methods in your bot, such as in the sample activity handler section below. For each of these handlers, there is no base implementation, so just add the logic that you want in your override.

There are certain situations where you will want to override the base turn handler, such as saving state at the end of a turn. When doing so, be sure to first call await base.OnTurnAsync(turnContext, cancellationToken); to make sure the base implementation of OnTurnAsync is run before your additional code. That base implementation is, among other things, responsible for calling the rest of the activity handlers such as OnMessageActivityAsync.

Activity handling

The bot logic processes incoming activities from one or more channels and generates outgoing activities in response.

The main bot logic is defined in the bot code. To implement a bot as an activity handler, derive your bot class from ActivityHandler, which implements the IBot interface. ActivityHandler defines various handlers for different types of activities, such as OnMessageActivityAsync, and OnMembersAddedAsync. These methods are protected, but can be overridden, since we're deriving from ActivityHandler.

The handlers defined in ActivityHandler are:

Event Handler Description
Any activity type received OnTurnAsync Calls one of the other handlers, based on the type of activity received.
Message activity received OnMessageActivityAsync Override this to handle a message activity.
Conversation update activity received OnConversationUpdateActivityAsync On a conversationUpdate activity, calls a handler if members other than the bot joined or left the conversation.
Non-bot members joined the conversation OnMembersAddedAsync Override this to handle members joining a conversation.
Non-bot members left the conversation OnMembersRemovedAsync Override this to handle members leaving a conversation.
Event activity received OnEventActivityAsync On an event activity, calls a handler specific to the event type.
Token-response event activity received OnTokenResponseEventAsync Override this to handle token response events.
Non-token-response event activity received OnEventAsync Override this to handle other types of events.
Message reaction activity received OnMessageReactionActivityAsync On a messageReaction activity, calls a handler if one or more reactions were added or removed from a message.
Message reactions added to a message OnReactionsAddedAsync Override this to handle reactions added to a message.
Message reactions removed from a message OnReactionsRemovedAsync Override this to handle reactions removed from a message.
Installation update activity received OnInstallationUpdateActivityAsync On an installationUpdate activity, calls a handler based on whether the bot was installed or uninstalled.
Bot installed OnInstallationUpdateAddAsync Override this to add logic for when the bot is installed within an organizational unit.
Bot uninstalled OnInstallationUpdateRemoveAsync Override this to add logic for when the bot is uninstalled within an organizational unit.
Other activity type received OnUnrecognizedActivityTypeAsync Override this to handle any activity type otherwise unhandled.

These different handlers have a turnContext that provides information about the incoming activity, which corresponds to the inbound HTTP request. Activities can be of various types, so each handler provides a strongly-typed activity in its turn context parameter; in most cases, OnMessageActivityAsync will always be handled, and is generally the most common.

As in previous 4.x versions of this framework, there is also the option to implement the public method OnTurnAsync. Currently, the base implementation of this method handles error checking and then calls each of the specific handlers (like the two we define in this sample) depending on the type of incoming activity. In most cases, you can leave that method alone and use the individual handlers, but if your situation requires a custom implementation of OnTurnAsync, it is still an option.

Important

If you do override the OnTurnAsync method, you'll need to call base.OnTurnAsync to get the base implementation to call all the other On<activity>Async handlers or call those handlers yourself. Otherwise, those handlers won't be called and that code won't be run.

Sample activity handler

For example, you can handle on members added to welcome users to a conversation, and handle on message to echo back messages they send to the bot.

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)
    {
        var welcomeText = "Hello and welcome!";
        foreach (var member in membersAdded)
        {
            if (member.Id != turnContext.Activity.Recipient.Id)
            {
                await turnContext.SendActivityAsync(MessageFactory.Text(welcomeText, welcomeText), cancellationToken);
            }
        }
    }
}

Next steps

  • The Microsoft Teams channel introduces some Teams-specific activities that your bot will need to support to work properly with Teams. To understand key concepts of developing bots for Microsoft Teams, see How Microsoft Teams bots work
  • An activity handler is a good way to design a bot that does not need to track conversational state between turns. The dialogs library provides ways to manage a long-running conversation with the user.