Respond to the task module submit action

Important

The code samples in this section are based on 4.6 and later versions of the Bot Framework SDK. If you're looking for documentation for earlier versions, see the Messaging Extensions - v3 SDK section in the Resources folder of the documentation.

This document guides you on how your app responds to the action commands, such as user's task module submit action. After a user submits the task module, your web service receives a composeExtension/submitAction invoke message with the command ID and parameter values. Your app has five seconds to respond to the invoke, otherwise the user receives an error message Unable to reach the app, and any reply to the invoke is ignored by the Teams client.

You have the following options to respond:

  • No response: Use the submit action to trigger a process in an external system, and not provide any feedback to the user. This is useful for long-running processes, and you can select to provide feedback alternately. For example, you can give feedback with a proactive message.
  • Another task module: You can respond with an additional task module as part of a multi-step interaction.
  • Card response: You can respond with a card that the user can interact with or insert into a message.
  • Adaptive Card from bot: Insert an Adaptive Card directly into the conversation.
  • Request the user to authenticate.
  • [Request the user to provide additional configuration]~/get-started/first-message-extension.md).

For authentication or configuration, after the user completes the process, the original invoke is resent to your web service. The following table shows which types of responses are available based on the invoke location commandContext of the messaging extension:

Response Type Compose Command bar Message
Card response
Another task module
Bot with Adaptive Card x
No response

Note

  • When you select Action.Submit through ME cards, it sends invoke activity with the name composeExtension, where the value is equal to the usual payload.
  • When you select Action.Submit through conversation, you receive message activity with the name onCardButtonClicked, where the value is equal to the usual payload.

The submitAction invoke event

Examples of receiving the invoke message are as follows:

protected override async Task<MessagingExtensionActionResponse> OnTeamsMessagingExtensionSubmitActionAsync(
  ITurnContext<IInvokeActivity> turnContext, MessagingExtensionAction action, CancellationToken cancellationToken) {
  //code to handle the submit action
}

Respond with a card inserted into the compose message area

The most common way to respond to the composeExtension/submitAction request is with a card inserted into the compose message area. The user submits the card to the conversation. For more information on using cards, see cards and card actions.

protected override async Task<MessagingExtensionActionResponse> OnTeamsMessagingExtensionSubmitActionAsync(
  ITurnContext<IInvokeActivity> turnContext, MessagingExtensionAction action, CancellationToken cancellationToken)
{
    var response = new MessagingExtensionActionResponse
    {
        ComposeExtension = new MessagingExtensionResult
        {
            AttachmentLayout = "list",
            Type = "result",
        },
    };
    var createCardData = ((JObject)action.Data).ToObject<CreateCardData>();
var card = new HeroCard
{
     Title = createCardData.Title,
     Subtitle = createCardData.Subtitle,
     Text = createCardData.Text,
};
    var attachments = new List<MessagingExtensionAttachment>();
    attachments.Add(new MessagingExtensionAttachment
    {
        Content = card,
        ContentType = HeroCard.ContentType,
        Preview = card.ToAttachment(),
    });
    response.ComposeExtension.Attachments = attachments;
    return response;
}

Respond with another task module

You can select to respond to the submitAction event with an additional task module. This is useful when:

  • You need to collect large amounts of information.
  • You need to dynamically change the information you are collecting based on user input.
  • You need to validate the information submitted by the user and resend the form with an error message if something is wrong.

The method for response is the same as responding to the initial fetchTask event. If you are using the Bot Framework SDK the same event triggers for both submit actions. To make this work, you must add logic that determines the correct response.

Bot response with Adaptive Card

Note

The prerequisite to get the bot response with an Adaptive card is that you must add the bot object to your app manifest, and define the required scope for the bot. Use the same ID as your messaging extension for your bot.

You can also respond to the submitAction by inserting a message with an Adaptive Card into the channel with a bot. The user can preview the message before submitting it. This is very useful in scenarios where you gather information from the users before creating an Adaptive Card response, or when you update the card after someone interacts with it.

The following scenario shows how the app Polly configures a poll without including the configuration steps in the channel conversation:

To configure the poll

  1. The user selects the messaging extension to invoke the task module.

  2. The user configures the poll with the task module.

  3. After submitting the task module, the app uses the information provided to build the poll as an Adaptive Card and sends it as a botMessagePreview response to the client.

  4. The user can then preview the Adaptive Card message before the bot inserts it into the channel. If the app is not already a member of the channel, select Send to add it.

    Note

    • The users can also select to Edit the message, which returns them to the original task module.
    • Interaction with the Adaptive Card changes the message before sending it.
  5. After the user selects Send the bot posts the message to the channel.

Respond to initial submit action

Your task module must respond to the initial composeExtension/submitAction message with a preview of the card that the bot sends to the channel. The user can verify the card before sending, and also try to install your bot in the conversation if the bot is not already installed.

protected override async Task<MessagingExtensionActionResponse> OnTeamsMessagingExtensionSubmitActionAsync(
  ITurnContext<IInvokeActivity> turnContext, MessagingExtensionAction action, CancellationToken cancellationToken)
{
  dynamic createCardData = ((JObject) action.Data).ToObject(typeof(JObject));
  var response = new MessagingExtensionActionResponse
  {
    ComposeExtension = new MessagingExtensionResult
    {
      Type = "botMessagePreview",
      ActivityPreview = MessageFactory.Attachment(new Attachment
      {
        Content = new AdaptiveCard("1.0")
        {
          Body = new List<AdaptiveElement>()
          {
            new AdaptiveTextBlock() { Text = "FormField1 value was:", Size = AdaptiveTextSize.Large },
            new AdaptiveTextBlock() { Text = Data["FormField1"] as string }
          },
          Height = AdaptiveHeight.Auto,
          Actions = new List<AdaptiveAction>()
          {
            new AdaptiveSubmitAction
            {
              Type = AdaptiveSubmitAction.TypeName,
              Title = "Submit",
              Data = new JObject { { "submitLocation", "messagingExtensionFetchTask" } },
            },
          }
        },
        ContentType = AdaptiveCard.ContentType
      }) as Activity
    }
  };

  return response;
}

The botMessagePreview send and edit events

Your messaging extension must respond to two new types of the composeExtension/submitAction invoke, where value.botMessagePreviewAction = "send"and value.botMessagePreviewAction = "edit".

protected override async Task<MessagingExtensionActionResponse> OnTeamsMessagingExtensionBotMessagePreviewEditAsync(
  ITurnContext<IInvokeActivity> turnContext, MessagingExtensionAction action, CancellationToken cancellationToken)
{
  //handle the event
}

protected override async Task<MessagingExtensionActionResponse> OnTeamsMessagingExtensionBotMessagePreviewSendAsync(
  ITurnContext<IInvokeActivity> turnContext, MessagingExtensionAction action, CancellationToken cancellationToken)
{
  //handle the event
}

Respond to botMessagePreview edit

If the user edits the card before sending, by selecting Edit, you receive a composeExtension/submitAction invoke with value.botMessagePreviewAction = edit. You must respond by returning the task module you sent, in response to the initial composeExtension/fetchTask invoke that began the interaction. This allows the user to start the process by re-entering the original information. Use the available information to update the task module so that the user need not fill out all information from scratch. For more information on responding to the initial fetchTask event, see responding to the initial fetchTask event.

Respond to botMessagePreview send

After the user selects the Send, you receive a composeExtension/submitAction invoke with value.botMessagePreviewAction = send. Your web service has to create and send a proactive message with the Adaptive Card to the conversation, and also reply to the invoke.

protected override async Task<MessagingExtensionActionResponse> OnTeamsMessagingExtensionBotMessagePreviewSendAsync(
  ITurnContext<IInvokeActivity> turnContext, MessagingExtensionAction action, CancellationToken cancellationToken)
{
  var activityPreview = action.BotActivityPreview[0];
  var attachmentContent = activityPreview.Attachments[0].Content;
  var previewedCard = JsonConvert.DeserializeObject<AdaptiveCard>(attachmentContent.ToString(),
          new JsonSerializerSettings { NullValueHandling = NullValueHandling.Ignore });
  
  previewedCard.Version = "1.0";

  var responseActivity = Activity.CreateMessageActivity();
  Attachment attachment = new Attachment()
  {
    ContentType = AdaptiveCard.ContentType,
    Content = previewedCard
  };
  responseActivity.Attachments.Add(attachment);
  
  // Attribute the message to the user on whose behalf the bot is posting
  responseActivity.ChannelData = new {
    OnBehalfOf = new []
    {
      new
      {
        ItemId = 0,
        MentionType = "person",
        Mri = turnContext.Activity.From.Id,
        DisplayName = turnContext.Activity.From.Name
      }  
    }
  };
  
  await turnContext.SendActivityAsync(responseActivity);

  return new MessagingExtensionActionResponse();
}

User attribution for bots messages

In scenarios where a bot sends messages on behalf of a user, attributing the message to that user helps with engagement and showcase a more natural interaction flow. This feature allows you to attribute a message from your bot to a user on whose behalf it was sent.

In the following image, on the left is a card message sent by a bot without user attribution and on the right is a card sent by a bot with user attribution.

user attribution bots

To use the user attribution in teams, you must add the OnBehalfOf mention entity to ChannelData in your Activity payload that is sent to Teams.

    OnBehalfOf = new []
    {
      new
      {
        ItemId = 0,
        MentionType = "person",
        Mri = turnContext.Activity.From.Id,
        DisplayName = turnContext.Activity.From.Name
      }  
    }

Details of OnBehalfOf entity schema

The following section is a description of the entities in the OnBehalfOf Array:

Field Type Description
itemId Integer Describes identification of the item. Its value must be 0.
mentionType String Describes the mention of a "person".
mri String Message resource identifier​ (MRI) of the person on whose behalf the message is sent. Message sender name would appear as "<user> through <bot name>".
displayName String Name of the person. Used as fallback in case name resolution is unavailable.

Code sample

Sample Name Description .NET Node.js
Teams messaging extension action Describes how to define action commands, create task module, and respond to task module submit action. View View
Teams messaging extension search Describes how to define search commands and respond to searches. View View

Next Step