Edit

Share via


Create and send dialogs

Important

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

You can create a modal dialog (referred as task module in TeamsJS v1.x) using an Adaptive Card or an embedded web view. To create a dialog, you must perform the process called the initial invoke request. This document covers the initial invoke request, payload activity properties when a dialog is invoked from 1:1 chat, group chat, channel (new post), channel (reply to thread), and command box.

Note

If you are not populating the dialog with parameters defined in the app manifest, you must create the dialog for users with either an Adaptive Card or an embedded web view.

The initial invoke request

In the process of the initial invoke request, your service receives an Activity object of type composeExtensions/fetchTask, and you must respond with a task object containing either an Adaptive Card or a URL to the embedded web view. Along with the standard bot activity properties, the initial invoke payload contains the following request metadata:

Property name Purpose
type Type of request. It must be invoke.
name Type of command that is issued to your service. It must be composeExtension/fetchTask.
from.id ID of the user that sent the request.
from.name Name of the user that sent the request.
from.aadObjectId Microsoft Entra object ID of the user that sent the request.
channelData.tenant.id Microsoft Entra tenant ID.
channelData.channel.id Channel ID (if the request was made in a channel).
channelData.team.id Team ID (if the request was made in a channel).
value.commandId Contains the ID of the command that was invoked.
value.commandContext The context that triggered the event. It must be compose.
value.context.theme The user's client theme, useful for embedded web view formatting. It must be default, contrast or dark.

Example

The code for the initial invoke request is given in the following example:

{
  "type": "invoke",
  "id": "f:bc319b1d-571a-194d-9ffb-11d7ab37c9ff",
  "from": {
    "id": "29:1aBjVi5MwCFfhPIV03E5uDdfpBFXp_2Yz-sjrvVg12oavg96cqpE_DiMhOpmN9zHeZpYbJcuUEKuSDy2AYWPz1A",
    "name": "Olo Brockhouse",
    "aadObjectId": "b130c271-d2eb-45f9-83ab-9eb3fe3788bc"
  }
  "channelData": {
    "tenant": {
      "id": "0d9b645f-597b-41f0-a2a3-ef103fbd91bb"
    },
    "source": {
      "name": "compose"
    }
  },
  "value": {
    "commandId": "Test",
    "commandContext": "compose",
    "requestId": "fe50f49e5c74440bb2ebf07f49e9553c",
    "context": {
      "theme": "default"
    }
  },
  "name": "composeExtension/fetchTask"

Payload activity properties when a dialog is invoked from 1:1 chat

The payload activity properties when a dialog is invoked from 1:1 chat are listed as follows:

Property name Purpose
type Type of request. It must be invoke.
name Type of command that is issued to your service. It must be composeExtension/fetchTask.
from.id ID of the user that sent the request.
from.name Name of the user that sent the request.
from.aadObjectId Microsoft Entra object ID of the user that sent the request.
channelData.tenant.id Microsoft Entra tenant ID.
channelData.source.name The source name from where dialog is invoked.
ChannelData.legacy. replyToId Gets or sets the ID of the message to which this message is a reply.
value.commandId Contains the ID of the command that was invoked.
value.commandContext The context that triggered the event. It must be compose.
value.context.theme The user's client theme, useful for embedded web view formatting. It must be default, contrast or dark.

Example

The payload activity properties when a dialog is invoked from 1:1 chat are given in the following example:

{
  "type": "invoke",
  "id": "f:bc319b1d-571a-194d-9ffb-11d7ab37c9ff",
  "from": {
    "id": "29:1aBjVi5MwCFfhPIV03E5uDdfpBFXp_2Yz-sjrvVg12oavg96cqpE_DiMhOpmN9zHeZpYbJcuUEKuSDy2AYWPz1A",
    "name": "Olo Brockhouse",
    "aadObjectId": "b130c271-d2eb-45f9-83ab-9eb3fe3788bc"
  }
  "channelData": {
    "tenant": {
      "id": "0d9b645f-597b-41f0-a2a3-ef103fbd91bb"
    },
    "source": {
      "name": "compose"
    }
  },
  "value": {
    "commandId": "Test",
    "commandContext": "compose",
    "requestId": "fe50f49e5c74440bb2ebf07f49e9553c",
    "context": {
      "theme": "default"
    }
  },
  "name": "composeExtension/fetchTask"
}

Payload activity properties when a dialog is invoked from a group chat

The payload activity properties when a dialog is invoked from a group chat are listed as follows:

Property name Purpose
type Type of request. It must be invoke.
name Type of command that is issued to your service. It must be composeExtension/fetchTask.
from.id ID of the user that sent the request.
from.name Name of the user that sent the request.
from.aadObjectId Microsoft Entra object ID of the user that sent the request.
channelData.tenant.id Microsoft Entra tenant ID.
channelData.source.name The source name from where dialog is invoked.
ChannelData.legacy. replyToId Gets or sets the ID of the message to which this message is a reply.
value.commandId Contains the ID of the command that was invoked.
value.commandContext The context that triggered the event. It must be compose.
value.context.theme The user's client theme, useful for embedded web view formatting. It must be default, contrast or dark.

Example

The payload activity properties when a dialog is invoked from a group chat are given in the following example:

{
  "type": "invoke",
  "id": "f:bf72031f-a17e-f99c-48dc-5c0714950d87",
  "from": {
    "id": "29:1aBjVi5MwCFfhPIV03E5uDdfpBFXp_2Yz-sjrvVg12oavg96cqpE_DiMhOpmN9zHeZpYbJcuUEKuSDy2AYWPz1A",
    "name": "Olo Brockhouse",
    "aadObjectId": "b130c271-d2eb-45f9-83ab-9eb3fe3788bc"
  },
  "conversation": {
    "isGroup": true,
    "conversationType": "groupChat",
    "id": "19:d77be72390a1416e9644261e9064fa00@thread.skype",
    "tenantId": "0d9b645f-597b-41f0-a2a3-ef103fbd91bb"
  },
  "channelData": {
    "tenant": {
      "id": "0d9b645f-597b-41f0-a2a3-ef103fbd91bb"
    },
    "source": {
      "name": "compose"
    }
  },
  "value": {
    "commandId": "Test",
    "commandContext": "compose",
    "requestId": "213167a1e3b6428b93e186ea5407c759",
    "context": {
      "theme": "default"
    }
  },
  "name": "composeExtension/fetchTask"
}

Payload activity properties when a dialog is invoked from a meeting chat

The payload activity properties when a dialog is invoked from a meeting chat are given in the following example:

{
   "type": "invoke",
   "id": "f:4d271f11-4eed-622f-e820-6d82bf91692f",
   "channelId": "msteams",
   "from": {
      "id": "29:1yLsdbTM1UjxqqD8cjduNUCI1jm8xZaH3lx9u5JQ04t2bknuTCkP45TXdfROTOWk1LzN1AqTgFZUEqHIVGn_qUA",
      "name": "MOD Administrator",
      "aadObjectId": "ef16aa89-5b26-4a2c-aebb-761b551577c0"
   },
   "conversation": {
      "tenantId": "c9f9aafd-64ac-4f38-8e05-12feba3fb090",
      "id": "19:meeting_NTk4ZDY4ZmYtOWEzZS00OTRkLThhY2EtZmUzZmUzMDQyM2M0@thread.v2",
      "name": "Test meeting"
   },   
   "channelData": {
      "tenant": {
         "id": "c9f9aafd-64ac-4f38-8e05-12feba3fb090"
      },
      "source": {
         "name": "compose"
      },
      "meeting": {
         "id": "MCMxOTptZWV0aW5nX05UazRaRFk0Wm1ZdE9XRXpaUzAwT1RSa0xUaGhZMkV0Wm1VelptVXpNRFF5TTJNMEB0aHJlYWQudjIjMA=="
      }
   },
   "value": {
      "commandId": "Test",
      "commandContext": "compose",
      "requestId": "c46a6b53573f42b5bc801716e5ccc960",
      "context": {
         "theme": "default"
      }
   },
   "name": "composeExtension/fetchTask",
}

Payload activity properties when a dialog is invoked from a channel (new post)

The payload activity properties when a dialog is invoked from a channel (new post) are listed as follows:

Property name Purpose
type Type of request. It must be invoke.
name Type of command that is issued to your service. It must be composeExtension/fetchTask.
from.id ID of the user that sent the request.
from.name Name of the user that sent the request.
from.aadObjectId Microsoft Entra object ID of the user that sent the request.
channelData.tenant.id Microsoft Entra tenant ID.
channelData.channel.id Channel ID (if the request was made in a channel).
channelData.team.id Team ID (if the request was made in a channel).
channelData.source.name The source name from where dialog is invoked.
ChannelData.legacy. replyToId Gets or sets the ID of the message to which this message is a reply.
value.commandId Contains the ID of the command that was invoked.
value.commandContext The context that triggered the event. It must be compose.
value.context.theme The user's client theme, useful for embedded web view formatting. It must be default, contrast, or dark.

Example

The payload activity properties when a dialog is invoked from a channel (new post) are given in the following example:

{
  "type": "invoke",
  "id": "f:a5fbb109-c989-c449-ee83-71ac99919d4b",
  "from": {
    "id": "29:1aBjVi5MwCFfhPIV03E5uDdfpBFXp_2Yz-sjrvVg12oavg96cqpE_DiMhOpmN9zHeZpYbJcuUEKuSDy2AYWPz1A",
    "name": "Olo Brockhouse",
    "aadObjectId": "b130c271-d2eb-45f9-83ab-9eb3fe3788bc"
  },
  "conversation": {
    "isGroup": true,
    "conversationType": "channel",
    "id": "19:6decf54d86d945e4b3924b63a9161a78@thread.skype",
    "name": "parsable",
    "tenantId": "0d9b645f-597b-41f0-a2a3-ef103fbd91bb"
  },
  "channelData": {
    "channel": {
      "id": "19:6decf54d86d945e4b3924b63a9161a78@thread.skype"
    },
    "team": {
      "id": "19:acca514e83cb497e960e0b014d405336@thread.skype"
    },
    "tenant": {
      "id": "0d9b645f-597b-41f0-a2a3-ef103fbd91bb"
    },
    "source": {
      "name": "compose"
    }
  },
  "value": {
    "commandId": "Test",
    "commandContext": "compose",
    "requestId": "5336640edc7748b28ce2df43f5b45963",
    "context": {
      "theme": "default"
    }
  },
  "name": "composeExtension/fetchTask"
}

Payload activity properties when a dialog is invoked from a channel (reply to thread)

The payload activity properties when a dialog is invoked from a channel (reply to thread) are listed as follows:

Property name Purpose
type Type of request. It must be invoke.
name Type of command that is issued to your service. It must be composeExtension/fetchTask.
from.id ID of the user that sent the request.
from.name Name of the user that sent the request.
from.aadObjectId Microsoft Entra object ID of the user that sent the request.
channelData.tenant.id Microsoft Entra tenant ID.
channelData.channel.id Channel ID (if the request was made in a channel).
channelData.team.id Team ID (if the request was made in a channel).
channelData.source.name The source name from where dialog is invoked.
ChannelData.legacy. replyToId Gets or sets the ID of the message to which this message is a reply.
value.commandId Contains the ID of the command that was invoked.
value.commandContext The context that triggered the event. It must be compose.
value.context.theme The user's client theme, useful for embedded web view formatting. It must be default, contrast or dark.

Example

The payload activity properties when a dialog is invoked from a channel (reply to thread) are given in the following example:

{
  "type": "invoke",
  "id": "f:19ccc884-c792-35ef-2f40-d0ff43dcca71",
  "from": {
    "id": "29:1aBjVi5MwCFfhPIV03E5uDdfpBFXp_2Yz-sjrvVg12oavg96cqpE_DiMhOpmN9zHeZpYbJcuUEKuSDy2AYWPz1A",
    "name": "Olo Brockhouse",
    "aadObjectId": "b130c271-d2eb-45f9-83ab-9eb3fe3788bc"
  },
  "conversation": {
    "isGroup": true,
    "conversationType": "channel",
    "id": "19:6decf54d86d945e4b3924b63a9161a78@thread.skype;messageid=1611060744833",
    "name": "parsable",
    "tenantId": "0d9b645f-597b-41f0-a2a3-ef103fbd91bb"
  },
  "channelData": {
    "channel": {
      "id": "19:6decf54d86d945e4b3924b63a9161a78@thread.skype"
    },
    "team": {
      "id": "19:acca514e83cb497e960e0b014d405336@thread.skype"
    },
    "tenant": {
      "id": "0d9b645f-597b-41f0-a2a3-ef103fbd91bb"
    },
    "source": {
      "name": "compose"
    }
  },
  "value": {
    "commandId": "TEst",
    "commandContext": "message",
    "requestId": "7f7d22efe5414818becebcec649a7912",
    "messagePayload": {
      "linkToMessage": "https://teams.microsoft.com/l/message/19:6decf54d86d945e4b3924b63a9161a78@thread.skype/1611060744833",
      "id": "1611060744833",
      "replyToId": null,
      "createdDateTime": "2021-01-19T12:52:24.833Z",
      "lastModifiedDateTime": null,
      "deleted": false,
      "summary": null,
      "importance": "normal",
      "locale": "en-us",
      "body": {
        "contentType": "html",
        "content": "<div><div><at id=\"0\">Testing outgoing Webhook-Nikitha</at> - Hi</div>\n</div>"
      },
      "from": {
        "device": null,
        "conversation": null,
        "user": {
          "userIdentityType": "aadUser",
          "id": "b130c271-d2eb-45f9-83ab-9eb3fe3788bc",
          "displayName": "Olo Brockhouse"
        },
        "application": null
      },
      "reactions": [],
      "mentions": [
        {
          "id": 0,
          "mentionText": "Testing outgoing Webhook-Nikitha",
          "mentioned": {
            "device": null,
            "conversation": null,
            "user": null,
            "application": {
              "applicationIdentityType": "webhook",
              "id": "b8c1c68c-e290-4bdd-81c3-266f310751dc",
              "displayName": "Testing outgoing Webhook-Nikitha"
            }
          }
        }
      ],
      "attachments": []
    },
    "context": {
      "theme": "default"
    }
  },
  "name": "composeExtension/fetchTask"
}

Payload activity properties when a dialog is invoked from a command box

The payload activity properties when a dialog is invoked from a command box are listed as follows:

Property name Purpose
type Type of request. It must be invoke.
name Type of command that is issued to your service. It must be composeExtension/fetchTask.
from.id ID of the user that sent the request.
from.name Name of the user that sent the request.
from.aadObjectId Microsoft Entra object ID of the user that sent the request.
channelData.tenant.id Microsoft Entra tenant ID.
channelData.source.name The source name from where dialog is invoked.
value.commandId Contains the ID of the command that was invoked.
value.commandContext The context that triggered the event. It must be compose.
value.context.theme The user's client theme, useful for embedded web view formatting. It must be default, contrast, or dark.

Example

The payload activity properties when a dialog is invoked from a command box are given in the following example:

{
  "type": "invoke",
  "id": "f:172560f1-95f9-3189-edb2-b7612cd1a3cd",
    "id": "29:1aBjVi5MwCFfhPIV03E5uDdfpBFXp_2Yz-sjrvVg12oavg96cqpE_DiMhOpmN9zHeZpYbJcuUEKuSDy2AYWPz1A",
    "name": "Olo Brockhouse",
    "aadObjectId": "b130c271-d2eb-45f9-83ab-9eb3fe3788bc"
  },
  "conversation": {
    "isGroup": true,
    "conversationType": "channel",
    "id": "19:6decf54d86d945e4b3924b63a9161a78@thread.skype",
    "name": "parsable",
    "tenantId": "0d9b645f-597b-41f0-a2a3-ef103fbd91bb"
  },
  "channelData": {
    "channel": {
      "id": "19:6decf54d86d945e4b3924b63a9161a78@thread.skype"
    },
    "team": {
      "id": "19:acca514e83cb497e960e0b014d405336@thread.skype"
    },
    "tenant": {
      "id": "0d9b645f-597b-41f0-a2a3-ef103fbd91bb"
    },
    "source": {
      "name": "compose"
    }
  },
  "value": {
    "commandId": "TEst",
    "commandContext": "compose",
    "requestId": "d2ce690cdc2b4920a538e75882610a30",
    "context": {
      "theme": "default"
    }
  },
  "name": "composeExtension/fetchTask"
}

Example

The following code section is an example of fetchTask request:

protected override async Task<MessagingExtensionActionResponse> OnTeamsMessagingExtensionFetchTaskAsync(ITurnContext<IInvokeActivity> turnContext, MessagingExtensionAction action, CancellationToken cancellationToken)
{
  //handle fetch task
}

Initial invoke request from a message

When your bot is invoked from a message, the value object in the initial invoke request must contain the details of the message that your message extension is invoked from. The reactions and mentions arrays are optional, and they are not present if there are no reactions or mentions in the original message. The following section is an example of the value object:

protected override async Task<MessagingExtensionActionResponse> OnTeamsMessagingExtensionFetchTaskAsync(ITurnContext<IInvokeActivity> turnContext, MessagingExtensionAction action, CancellationToken cancellationToken)
{
  var messageText = action.MessagePayload.Body.Content;
  var fromId = action.MessagePayload.From.User.Id;

  //finish handling the fetchTask
}

Respond to the fetchTask

Respond to the invoke request with a task object that contains either a taskInfo object with the Adaptive Card or web URL, or a simple string message.

Property name Purpose
type Can be either continue to present a form, or message for a simple pop-up.
value Either a taskInfo object for a form, or a string for a message.

The schema for the taskInfo object is:

Property name Purpose
title The title of the dialog.
height It must be either an integer (in pixels), or small, medium, large.
width It must be either an integer (in pixels), or small, medium, large.
card The Adaptive Card defining the form (if using one).
url The URL to be opened inside of the dialog as an embedded web view.
fallbackUrl If a client does not support the dialog feature, this URL is opened in a browser tab.

Respond to the fetchTask with an Adaptive Card

When using an Adaptive Card, you must respond with a task object with the value object containing an Adaptive Card.

Example

The following code section is an example to fetchTask response with an Adaptive Card:

This sample uses the AdaptiveCards NuGet package in addition to the Bot Framework SDK.

protected override async Task<MessagingExtensionActionResponse> OnTeamsMessagingExtensionFetchTaskAsync(ITurnContext<IInvokeActivity> turnContext, MessagingExtensionAction action, CancellationToken cancellationToken)
{
  string placeholder = "Not invoked from message";

  if (action.MessagePayload != null)
  {
      var messageText = action.MessagePayload.Body.Content;
      var fromId = action.MessagePayload.From.User.Id;
      placeholder = "Invoked from message";
  }

  var response = new MessagingExtensionActionResponse()
  {
    Task = new TaskModuleContinueResponse()
    {
      Value = new TaskModuleTaskInfo()
      {
        Height = "small",
        Width = "small",
        Title = "Example dialog",
        Card = new Attachment()
        {
          ContentType = AdaptiveCard.ContentType,
          Content = new AdaptiveCard("1.0")
          {
            Body = new List<AdaptiveElement>()
            {
              new AdaptiveTextInput() { Id = "FormField1", Placeholder = placeholder},
              new AdaptiveTextInput() { Id = "FormField2", Placeholder = "FormField2"},
              new AdaptiveTextInput() { Id = "FormField3", Placeholder = "FormField3"},
            },
            Actions = new List<AdaptiveAction>()
            {
              new AdaptiveSubmitAction()
              {
                Type = AdaptiveSubmitAction.TypeName,
                Title = "Submit",
              },
            },
          },
        },
      },
    },
  };
  return response;
}

Create a dialog with an embedded web view

When using an embedded web view, you must respond with a task object with the value object containing the URL to the web form that you want to load. The domains of any URL you want to load must be included in the validDomains array in your app's manifest. For more information on building your embedded web view, see the dialog documentation.

protected override async Task<MessagingExtensionActionResponse> OnTeamsMessagingExtensionFetchTaskAsync(ITurnContext<IInvokeActivity> turnContext, MessagingExtensionAction action, CancellationToken cancellationToken)
{
  string placeholder = "Not invoked from message";

  if (action.MessagePayload != null)
  {
      var messageText = action.MessagePayload.Body.Content;
      var fromId = action.MessagePayload.From.User.Id;
      placeholder = "Invoked from message";
  }

  var response = new MessagingExtensionActionResponse()
  {
    Task = new TaskModuleContinueResponse()
    {
      Value = new TaskModuleTaskInfo()
      {
        Height = "small",
        Width = "small",
        Title = "Example dialog",
        Url = "https://contoso.com/msteams/taskmodules/newcustomer",
        },
      },
    },
  };
  return response;
}

Request to install your conversational bot

If the app contains a conversational bot, install the bot in the conversation and then load the dialog. The bot is useful to get additional context for the dialog. An example for this scenario is to fetch the roster to populate a people picker control or the list of channels in a team.

When the message extension receives the composeExtensions/fetchTask invoke, check if the bot is installed in the current context to facilitate the flow. For example, check the flow with a get roster call. If the bot is not installed, return an Adaptive Card with an action that requests the user to install the bot. The user must have the permission to install the apps in that location for checking. If the app installation is unsuccessful, the user receives a message to contact the administrator.

Example

The following code section is an example of the response:

{
  "type": "AdaptiveCard",
  "body": [
    {
      "type": "TextBlock",
      "text": "Looks like you haven't used Disco in this team/chat"
    }
  ],
  "actions": [
    {
      "type": "Action.Submit",
      "title": "Continue",
      "data": {
        "msteams": {
          "justInTimeInstall": true
        }
      }
    }
  ],
  "version": "1.0"
}

After the installation of conversational bot, it receives another invoke message with name = composeExtensions/submitAction, and value.data.msteams.justInTimeInstall = true.

Example

The following code section is an example of the task response to the invoke:

{
  "value": {
    "commandId": "giveKudos",
    "commandContext": "compose",
    "context": {
      "theme": "default"
    },
    "data": {
      "msteams": {
        "justInTimeInstall": true
      }
    }
  },
  "conversation": {
    "id": "19:7705841b240044b297123ad7f9c99217@thread.skype"
  },
  "name": "composeExtension/submitAction",
  "imdisplayname": "Bob Smith"
}

The task response to the invoke must be similar to that of the installed bot.

Example

The following code section is an example of just-in time installation of app with Adaptive card:

private static Attachment GetAdaptiveCardAttachmentFromFile(string fileName)
  {
      //Read the card json and create attachment.
         string[] paths = { ".", "Resources", fileName };
         var adaptiveCardJson = File.ReadAllText(Path.Combine(paths));
         var adaptiveCardAttachment = new Attachment()
            {
                ContentType = "application/vnd.microsoft.card.adaptive",
                Content = JsonConvert.DeserializeObject(adaptiveCardJson),
            };
            return adaptiveCardAttachment;
        }

Code sample

Sample name Description .NET Node.js Python Manifest
Teams message extension action This sample shows how to define action commands, create dialog, and respond to dialog submit action. View View View View
Message extension action preview This sample shows how to use action preview in Messaging Extensions using Bot Framework v4. View View NA View
Teams message extension search This sample shows how to build a Search-based Message Extension. It searches nudget packages and displays the results in search based messaging extension. View View View View

Next step

See also