Search code examples
c#botframeworkmicrosoft-teamsazure-bot-service

How do you handle CardAction Button Clicks in Bot Framework .NET for Teams?


I built a bot using the Microsoft.Bot.Builder.Azure 4.12.2 connected to MS Teams via the Azure Bot Service. I have a message with a Hero Card attachment containing a set of buttons. When a user clicks on a button, the value of the card is sent back to the bot as a message, but there doesn't seem to be any other information attached to identify that the message was a button click as opposed to a message. I'd like to understand how to properly handle the button click.

I'll show my code to demonstrate...

public class MyBot : ActivityHandler
{ 
    protected override async Task OnMessageActivityAsync(
        ITurnContext<IMessageActivity> turnContext,
        CancellationToken cancellationToken)
    {
        var activity = turnContext.Activity;
        if (activity.Text is "test")
        {
            var heroCard = new HeroCard
            {
                Buttons = new List<CardAction>
                {
                    new(ActionTypes.ImBack)
                    {
                       Title = "Cup 1",
                       DisplayText = "You chose Cup1",
                       Value = "cup1",
                       ChannelData = new { id = 1, status = "wise" }
                    },
                    new(ActionTypes.ImBack)
                    {
                        Title = "Cup 2",
                        DisplayText = "You chose Cup2",
                        Value = "cup2",
                        ChannelData = new { id = 1, status = "unwise" }
                    }
                }
            };
            var response = MessageFactory.Text("Choose wisely");
            response.Attachments.Add(heroCard.ToAttachment());
            await turnContext.SendActivityAsync(response, cancellationToken);
            return;
        }

        // How can I tell that they actually clicked the Cup 1 button and didn't just type "cup1"?
        if (activity.Text is "cup1")
        {
            await turnContext.SendActivityAsync(MessageFactory.Text("you chose wisely."), cancellationToken);
        }
        else
        {
            await turnContext.SendActivityAsync(MessageFactory.Text("you chose unwisely."), cancellationToken);
        }
    }
}

And here's an example of it in action.

Teams session

Here's the sequence of activities.

  1. I send a message "test" to the bot.
  2. Bot responds with a message containing two buttons.
  3. I click the first button.
  4. Bot responds that I chose wisely.
  5. I type "cup1"
  6. Bot responds that I chose wisely.

What I want to be able to do is have the bot ignore if I type "cup1" because that's not a button click. When I examine the IMessageActivity the bot receives on the button click, there doesn't seem to be anything that indicates it's a button click. Any help is appreciated!


Solution

  • The ImBack action is designed to simulate a message as if the user had sent it to you by text. They are intended to be used as an alternative to your user typing a message, so the behavior above is sort of the expected norm.

    That being said, you have a few options to achieve what you're going for. The first would be to usethe messageBack action type for you buttons. That would give you more control and make it easier to determine button click v's text message.

    The second option would be to use Adaptive Cards, and their actions (in this case either action.submit or action.execute depending on your desired behavior), rather than a Hero Card. This would probably be my suggested solution for Teams, as Adaptive Cards give you vastly more flexibility than Hero Cards.

    The full documentation for card actions in Teams can be found here: https://learn.microsoft.com/en-us/microsoftteams/platform/task-modules-and-cards/cards/cards-actions, but I've also given an example messageBack action below.

    {
      "buttons": [
        {
        "type": "messageBack",
        "title": "My MessageBack button",
        "displayText": "I clicked this button",
        "text": "User just clicked the MessageBack button",
        "value": "{\"property\": \"propertyValue\" }"
        }
      ]
    }