Updates from: 12/02/2022 03:24:57
Service Microsoft Docs article Related commit history on GitHub Change details
platform Meeting Apps Apis https://github.com/MicrosoftDocs/msteams-docs/commits/main/msteams-platform/apps-in-teams-meetings/meeting-apps-apis.md
The following table includes the query parameters:
# [C#](#tab/dotnet)
+* [SDK reference](/dotnet/api/microsoft.bot.builder.teams.teamsinfo.getmeetingparticipantasync?view=botbuilder-dotnet-stable&preserve-view=true)
+* [Sample code reference](https://github.com/OfficeDev/Microsoft-Teams-Samples/blob/main/samples/meetings-context-app/csharp/MeetingContextApp/Bots/MeetingContextBot.cs#L19)
+ ```csharp protected override async Task OnMessageActivityAsync(ITurnContext<IMessageActivity> turnContext, CancellationToken cancellationToken) {
+ // Gets the details for the given meeting participant.
+ // This only works in Teams meeting scoped conversations.
TeamsMeetingParticipant participant = await TeamsInfo.GetMeetingParticipantAsync(turnContext, "yourMeetingId", "yourParticipantId", "yourParticipantTenantId").ConfigureAwait(false); TeamsChannelAccount member = participant.User; MeetingParticipantInfo meetingInfo = participant.Meeting; ConversationAccount conversation = participant.Conversation;
+ // Sends a message activity to the sender of the incoming activity.
await turnContext.SendActivityAsync(MessageFactory.Text($"The participant role is: {meetingInfo.Role}"), cancellationToken); } ``` # [JavaScript](#tab/javascript)
+* [SDK reference](/javascript/api/botbuilder/teamsinfo?view=botbuilder-ts-latest#botbuilder-teamsinfo-getmeetingparticipant&preserve-view=true)
+* [Sample code reference](https://github.com/OfficeDev/Microsoft-Teams-Samples/blob/main/samples/meetings-token-app/nodejs/server/bot/botActivityHandler.js#L30)
```typescript export class MyBot extends TeamsActivityHandler { constructor() { super(); this.onMessage(async (context, next) => {+
+ // getMeetingParticipant : Gets the details for the given meeting participant.
+ // This only works in Teams meeting scoped conversations.
TeamsMeetingParticipant participant = getMeetingParticipant(turnContext, "yourMeetingId", "yourParticipantId", "yourTenantId"); let member = participant.user; let meetingInfo = participant.meeting; let conversation = participant.conversation;
-
+
+ // Sends a message activity to the sender of the incoming activity.
await context.sendActivity(`The participant role is: '${meetingInfo.role}'`);+
+ // By calling next() you ensure that the next BotHandler is run.
await next(); }); }
The `Bot ID` is declared in the manifest and the bot receives a result object.
# [C#](#tab/dotnet)
+* [SDK reference](/dotnet/api/microsoft.bot.builder.teams.teamsactivityextensions.teamsnotifyuser?view=botbuilder-dotnet-stable#microsoft-bot-builder-teams-teamsactivityextensions-teamsnotifyuser(microsoft-bot-schema-iactivity)&preserve-view=true)
+* [Sample code reference](https://github.com/OfficeDev/Microsoft-Teams-Samples/blob/main/samples/bot-proactive-messaging/csharp/proactive-cmd/Program.cs)
+ ```csharp
+// Specifies the type of text data in a message attachment.
Activity activity = MessageFactory.Text("This is a meeting signal test");+
+// Configures the current activity to generate a notification within Teams.
activity.TeamsNotifyUser(true, "https://teams.microsoft.com/l/bubble/APP_ID?url=<url>&height=<height>&width=<width>&title=<title>&completionBotId=BOT_APP_ID");+
+// Sends a message activity to the sender of the incoming activity.
await turnContext.SendActivityAsync(activity).ConfigureAwait(false); ``` # [JavaScript](#tab/javascript)
+* [SDK reference](/javascript/api/botbuilder-core/turncontext?view=botbuilder-ts-latest#botbuilder-core-turncontext-sendactivity&preserve-view=true)
+* [Sample code reference](https://github.com/OfficeDev/Microsoft-Teams-Samples/blob/main/samples/bot-conversation/nodejs/bots/teamsConversationBot.js#L74)
```javascript
+// MessageFactory.text(): Specifies the type of text data in a message attachment.
const replyActivity = MessageFactory.text('Hi'); // this could be an adaptive card instead replyActivity.channelData = { notification: {
replyActivity.channelData = {
externalResourceUrl: 'https://teams.microsoft.com/l/bubble/APP_ID?url=<url>&height=<height>&width=<width>&title=<title>&completionBotId=BOT_APP_IDΓÇÖ } };+
+// Sends a message activity to the sender of the incoming activity.
await context.sendActivity(replyActivity); ```
POST /v3/conversations/{conversationId}/activities
``` ```json-
+// In-meeting notification response
{ "type": "message", "text": "John Phillips assigned you a weekly todo",
The following table lists the query parameter:
# [C#](#tab/dotnet)
+* [SDK reference](/dotnet/api/microsoft.bot.builder.teams.teamsinfo.getmeetinginfoasync?view=botbuilder-dotnet-stable#microsoft-bot-builder-teams-teamsinfo-getmeetinginfoasync(microsoft-bot-builder-iturncontext-system-string-system-threading-cancellationtoken)&preserve-view=true)
+* [Sample code reference](https://github.com/OfficeDev/Microsoft-Teams-Samples/blob/main/samples/graph-meeting-notification/csharp/MeetingNotification/Bots/MeetingNotificationBot.cs#L56)
+ ```csharp
+// Gets the information for the given meeting id.
MeetingInfo result = await TeamsInfo.GetMeetingInfoAsync(turnContext);+
+// Sends a message activity to the sender of the incoming activity.
await turnContext.SendActivityAsync(JsonConvert.SerializeObject(result)); ```
The following code shows how to capture the metadata of a meeting that is `Meeti
Meeting Start Event
+* [Sample code reference](https://github.com/OfficeDev/Microsoft-Teams-Samples/blob/main/samples/meetings-events/csharp/MeetingEvents/Bots/ActivityBot.cs#L34)
+ ```csharp
+// Invoked when a Teams Meeting Start event activity is received from the connector.
protected override async Task OnTeamsMeetingStartAsync(MeetingStartEventDetails meeting, ITurnContext<IEventActivity> turnContext, CancellationToken cancellationToken) {
+ // Sends a message activity to the sender of the incoming activity.
await turnContext.SendActivityAsync(JsonConvert.SerializeObject(meeting)); } ``` Meeting End Event
+* [Sample code reference](https://github.com/OfficeDev/Microsoft-Teams-Samples/blob/main/samples/meetings-events/csharp/MeetingEvents/Bots/ActivityBot.cs#L51)
+ ```csharp
+// Invoked when a Teams Meeting End event activity is received from the connector.
protected override async Task OnTeamsMeetingEndAsync(MeetingEndEventDetails meeting, ITurnContext<IEventActivity> turnContext, CancellationToken cancellationToken) {
+ // Sends a message activity to the sender of the incoming activity.
await turnContext.SendActivityAsync(JsonConvert.SerializeObject(meeting)); } ```
callback = (errcode, result) => {
// Handle success code } }-
+// The getIncomingClientAudioState API shows the current audio state.
microsoftTeams.meeting.getIncomingClientAudioState(this.callback) ```
callback = (error, result) => {
// Handle success code } }-
+// The toggleIncomingClientAudio API allows an app to toggle the incoming audio state.
microsoftTeams.meeting.toggleIncomingClientAudio(this.callback) ```
platform Bot Features https://github.com/MicrosoftDocs/msteams-docs/commits/main/msteams-platform/bots/bot-features.md
The following code provides an example of bot activity for a channel team scope:
# [C#](#tab/dotnet)
+* [SDK reference](/dotnet/api/microsoft.bot.builder.activityhandler.onmessageactivityasync?view=botbuilder-dotnet-stable#microsoft-bot-builder-activityhandler-onmessageactivityasync(microsoft-bot-builder-iturncontext((microsoft-bot-schema-imessageactivity))-system-threading-cancellationtoken)&preserve-view=true)
+* [Sample code reference](https://github.com/OfficeDev/Microsoft-Teams-Samples/blob/main/samples/app-localization/csharp/Localization/Bots/LocalizerBot.cs#L20)
+ ```csharp protected override async Task OnMessageActivityAsync(ITurnContext<IMessageActivity> turnContext, CancellationToken cancellationToken)
protected override async Task OnMessageActivityAsync(ITurnContext<IMessageActivi
var mention = new Mention { Mentioned = turnContext.Activity.From,
+ // EncodeName: Converts the name to a valid XML name.
Text = $"<at>{XmlConvert.EncodeName(turnContext.Activity.From.Name)}</at>", };-
+
+ // MessageFactory.Text(): Specifies the type of text data in a message attachment.
var replyActivity = MessageFactory.Text($"Hello {mention.Text}."); replyActivity.Entities = new List<Entity> { mention };
+ // Sends a message activity to the sender of the incoming activity.
await turnContext.SendActivityAsync(replyActivity, cancellationToken); }
protected override async Task OnMessageActivityAsync(ITurnContext<IMessageActivi
# [Node.js](#tab/nodejs)
+* [SDK reference](/javascript/api/botbuilder-core/activityhandler?view=botbuilder-ts-latest#botbuilder-core-activityhandler-onmessage&preserve-view=true)
+* [Sample code reference](https://github.com/OfficeDev/Microsoft-Teams-Samples/blob/main/samples/app-localization/nodejs/server/bot/botActivityHandler.js#L25)
+ ```javascript this.onMessage(async (turnContext, next) => { const mention = { mentioned: turnContext.activity.from,+
+ // TextEncoder().encode(): Encodes the supplied characters.
text: `<at>${ new TextEncoder().encode(turnContext.activity.from.name) }</at>`, } as Mention;
+ // MessageFactory.text(): Specifies the type of text data in a message attachment.
const replyActivity = MessageFactory.text(`Hello ${mention.text}`); replyActivity.entities = [mention];
The following code provides an example of bot activity for a one-to-one chat:
# [C#](#tab/dotnet)
+* [SDK reference](/dotnet/api/microsoft.bot.schema.activityextensions.removerecipientmention?view=botbuilder-dotnet-stable#microsoft-bot-schema-activityextensions-removerecipientmention(microsoft-bot-schema-imessageactivity)&preserve-view=true)
+* [Sample code reference](https://github.com/OfficeDev/Microsoft-Teams-Samples/blob/main/samples/app-hello-world/csharp/Microsoft.Teams.Samples.HelloWorld.Web/Bots/MessageExtension.cs#L19)
+ ```csharp // Handle message activity protected override async Task OnMessageActivityAsync(ITurnContext<IMessageActivity> turnContext, CancellationToken cancellationToken) {
+ // Remove recipient mention text from Text property.
+ // Use with caution because this function is altering the text on the Activity.
turnContext.Activity.RemoveRecipientMention(); var text = turnContext.Activity.Text.Trim().ToLower();
- await turnContext.SendActivityAsync(MessageFactory.Text($"Your message is {text}."), cancellationToken);
+
+ // Sends a message activity to the sender of the incoming activity.
+ await turnContext.SendActivityAsync(MessageFactory.Text($"Your message is {text}."), cancellationToken);
} ``` # [Node.js](#tab/nodejs)
+[Sample code reference](https://github.com/OfficeDev/Microsoft-Teams-Samples/blob/main/samples/bot-receive-channel-messages-withRSC/nodejs/server/bot/botActivityHandler.js#L20)
+ ```javascript this.onMessage(async (context, next) => {
+ // MessageFactory.text(): Specifies the type of text data in a message attachment.
await context.sendActivity(MessageFactory.text("Your message is:" + context.activity.text)); await next(); });
platform Channel And Group Conversations https://github.com/MicrosoftDocs/msteams-docs/commits/main/msteams-platform/bots/how-to/conversations/channel-and-group-conversations.md
Bots in a group or channel only receive messages when they're mentioned @botname
See the following video to learn about channel and group chat conversations with a bot: <br>
-> [!VIDEO https://www.microsoft.com/en-us/videoplayer/embed/RE4NzEs]
+> [!VIDEO <https://www.microsoft.com/en-us/videoplayer/embed/RE4NzEs>]
<br> ## Design guidelines
The following code shows an example of retrieving mentions:
# [C#](#tab/dotnet)
+* [SDK reference](/dotnet/api/microsoft.bot.schema.activity.getmentions?view=botbuilder-dotnet-stable#microsoft-bot-schema-activity-getmentions&preserve-view=true)
+* [Sample code reference](https://github.com/OfficeDev/Microsoft-Teams-Samples/blob/main/samples/bot-archive-groupchat-messages/csharp/FetchGroupChatMessages/Bots/ActivityBot.cs#L182)
+ ```csharp protected override async Task OnMessageActivityAsync(ITurnContext<IMessageActivity> turnContext, CancellationToken cancellationToken) {
+ // Resolves the mentions from the entities activity.
Mention[] mentions = turnContext.Activity.GetMentions(); if(mentions != null) { ChannelAccount firstMention = mentions[0].Mentioned;+
+ // Sends a message activity to the sender of the incoming activity.
await turnContext.SendActivityAsync($"Hello {firstMention.Name}"); } else {
+ // Sends a message activity to the sender of the incoming activity.
await turnContext.SendActivityAsync("Aw, no one was mentioned."); } } ``` # [TypeScript](#tab/typescript)
+* [SDK reference](/javascript/api/botbuilder-core/turncontext?view=botbuilder-ts-latest#botbuilder-core-turncontext-getmentions&preserve-view=true)
```typescript this.onMessage(async (turnContext, next) => {
+
+ // Resolves the mentions from the entities activity.
const mentions = TurnContext.getMentions(turnContext.activity); if (mentions){ const firstMention = mentions[0].mentioned;+
+ // Sends a message activity to the sender of the incoming activity.
await turnContext.sendActivity(`Hello ${firstMention.name}.`); } else {
+ // Sends a message activity to the sender of the incoming activity.
await turnContext.sendActivity(`Aw, no one was mentioned.`); } await next(); });+ ``` # [JSON](#tab/json)
+* [SDK reference](/microsoftteams/platform/resources/bot-v3/bot-conversations/bots-conv-channel#example-outgoing-message-with-user-mentioned)
+ ```json { "type": "message",
this.onMessage(async (turnContext, next) => {
``` # [Python](#tab/python)
+* [SDK reference](/python/api/botbuilder-schema/botbuilder.schema.activity?view=botbuilder-py-latest#botbuilder-schema-activity-get-mentions&preserve-view=true)
```python @staticmethod
+// Resolves the mentions from the entities of this activity.
def get_mentions(activity: Activity) -> List[Mention]:     result: List[Mention] = []     if activity.entities is not None:
The following code shows an example of adding mentions to your messages:
# [C#](#tab/dotnet)
+* [SDK reference](/dotnet/api/microsoft.bot.builder.activityhandler.onmessageactivityasync?view=botbuilder-dotnet-stable&preserve-view=true)
+* [Sample code reference](https://github.com/OfficeDev/Microsoft-Teams-Samples/blob/main/samples/bot-conversation/csharp/Bots/TeamsConversationBot.cs#L38)
+ ```csharp protected override async Task OnMessageActivityAsync(ITurnContext<IMessageActivity> turnContext, CancellationToken cancellationToken) {
protected override async Task OnMessageActivityAsync(ITurnContext<IMessageActivi
Text = $"<at>{XmlConvert.EncodeName(turnContext.Activity.From.Name)}</at>", };
+ // Returns a simple text message.
var replyActivity = MessageFactory.Text($"Hello {mention.Text}."); replyActivity.Entities = new List<Entity> { mention };
+ // Sends an activity to the sender of the incoming activity.
await turnContext.SendActivityAsync(replyActivity, cancellationToken); }+ ``` # [TypeScript](#tab/typescript)
this.onMessage(async (turnContext, next) => {
text: `<at>${ new TextEncoder().encode(turnContext.activity.from.name) }</at>`, } as Mention;
+ // Returns a simple text message.
const replyActivity = MessageFactory.text(`Hello ${mention.text}`); replyActivity.entities = [mention];
+ // Sends a message activity to the sender of the incoming activity.
await turnContext.sendActivity(replyActivity); // By calling next() you ensure that the next BotHandler is run. await next(); });+ ``` # [JSON](#tab/json) The `text` field in the object in the `entities` array must match a portion of the message `text` field. If it doesn't, the mention is ignored.
+* [SDK reference](/microsoftteams/platform/resources/bot-v3/bot-conversations/bots-conv-channel#example-outgoing-message-with-user-mentioned)
+ ```json { "type": "message",
The `text` field in the object in the `entities` array must match a portion of t
# [Python](#tab/python)
+* [Sample code reference](https://github.com/OfficeDev/Microsoft-Teams-Samples/blob/main/samples/bot-conversation/python/bots/teams_conversation_bot.py#L94)
+ ```python async def _mention_activity(self, turn_context: TurnContext): mention = Mention(
async def _mention_activity(self, turn_context: TurnContext):
text=f"<at>{turn_context.activity.from_property.name}</at>", type="mention" )-
+ // Returns a simple text message.
reply_activity = MessageFactory.text(f"Hello {mention.text}")
+ # Sends a message activity to the sender of the incoming activity.
reply_activity.entities = [Mention().deserialize(mention.serialize())] await turn_context.send_activity(reply_activity) ```
Follow the [step-by-step guide](../../../sbs-teams-conversation-bot.yml), create
## Next step > [!div class="nextstepaction"]
-> [Conversation events in your Teams bot](subscribe-to-conversation-events.md)
+> [Subscribe to conversation events](~/bots/how-to/conversations/subscribe-to-conversation-events.md)
## See also
-* [Build bots for Teams](../../what-are-bots.md)
-* [Authenticate users in Microsoft Teams](../../../concepts/authentication/authentication.md)
-* [Task modules](../../../task-modules-and-cards/what-are-task-modules.md)
-* [Upload file in Teams using bot](../../../sbs-file-handling-in-bot.yml)
-* [Get Teams specific context for your bot](../get-teams-context.md)
+* [Get Teams context](~/bots/how-to/get-teams-context.md)
* [Create private channel on behalf of user](/graph/api/channel-post#example-2-create-private-channel-on-behalf-of-user) * [Connect a bot to Web Chat channel](/azure/bot-service/bot-service-channel-connect-webchat)
platform Channel Messages With Rsc https://github.com/MicrosoftDocs/msteams-docs/commits/main/msteams-platform/bots/how-to/conversations/channel-messages-with-rsc.md
The following code provides an example of the RSC permissions:
# [C#](#tab/dotnet)
+* [SDK reference](/dotnet/api/microsoft.bot.builder.activityhandler.onmessageactivityasync?view=botbuilder-dotnet-stable&preserve-view=true)
+* [Sample code reference](https://github.com/OfficeDev/Microsoft-Teams-Samples/blob/main/samples/meetings-token-app/csharp/Bots/TokenBot.cs#L52)
+ ```csharp
-// Handle when a message is addressed to the bot.
-// When rsc is enabled the method will be called even when bot is addressed without being @mentioned
+// Handle when a message is addressed to the bot.
+// When rsc is enabled the method will be called even when bot is addressed without being @mentioned.
protected override async Task OnMessageActivityAsync(ITurnContext<IMessageActivity> turnContext, CancellationToken cancellationToken) {
+ // Sends an activity to the sender of the incoming activity.
await turnContext.SendActivityAsync(MessageFactory.Text("Using RSC the bot can receive messages across channels or chats in team without being @mentioned.")); }+ ``` # [Node.js](#tab/nodejs)
+* [Sample code reference](https://github.com/OfficeDev/Microsoft-Teams-Samples/blob/main/samples/app-localization/nodejs/server/bot/botActivityHandler.js#L25)
+ ```javascript
-// Handle when a message is addressed to the bot.
-// When rsc is enabled the method will be called even when bot is addressed without being @mentioned
+// Handle when a message is addressed to the bot.
+// When rsc is enabled the method will be called even when bot is addressed without being @mentioned.
+ this.onMessage(async (context, next) => {
+ // Sends a message activity to the sender of the incoming activity.
await context.sendActivity(MessageFactory.text("Using RSC the bot can receive messages across channels or chats in team without being @mentioned.")) await next(); });+ ```
this.onMessage(async (context, next) => {
## See also
-* [Build bots for Teams](../../what-are-bots.md)
+* [Bot conversations](/microsoftteams/platform/bots/how-to/conversations/conversation-basics)
* [Resource-specific consent](/microsoftteams/resource-specific-consent)
-* [Test resource-specific consent](../../../graph-api/rsc/test-resource-specific-consent.md#prerequisites)
+* [Test resource-specific consent](/microsoftteams/platform/graph-api/rsc/test-resource-specific-consent)
* [Upload custom app in Teams](~/concepts/deploy-and-publish/apps-upload.md)
-* [Authorization permissions](../../../resources/schem#authorization)
* [List replies to messages in a channel](/graph/api/chatmessage-list-replies?view=graph-rest-1.0&tabs=http&preserve-view=true)
platform Conversation Messages https://github.com/MicrosoftDocs/msteams-docs/commits/main/msteams-platform/bots/how-to/conversations/conversation-messages.md
The following code shows an example of receiving a message:
# [C#](#tab/dotnet)
+* [SDK reference](/dotnet/api/microsoft.bot.builder.activityhandler.onmessageactivityasync?view=botbuilder-dotnet-stable&preserve-view=true)
+* [Sample code reference](https://github.com/OfficeDev/Microsoft-Teams-Samples/blob/main/samples/meetings-token-app/csharp/Bots/TokenBot.cs#L52)
+ ```csharp protected override async Task OnMessageActivityAsync(ITurnContext<IMessageActivity> turnContext, CancellationToken cancellationToken) {
+ // Sends an activity to the sender of the incoming activity.
await turnContext.SendActivityAsync(MessageFactory.Text($"Echo: {turnContext.Activity.Text}"), cancellationToken); }- ``` # [TypeScript](#tab/typescript)
-```typescript
+* [Sample code reference](https://github.com/OfficeDev/Microsoft-Teams-Samples/blob/main/samples/app-localization/nodejs/server/bot/botActivityHandler.js#L25)
+```typescript
export class MyBot extends TeamsActivityHandler { constructor() { super(); this.onMessage(async (context, next) => {
+ // Sends a message activity to the sender of the incoming activity.
await context.sendActivity(`Echo: '${context.activity.text}'`); await next(); });
export class MyBot extends TeamsActivityHandler {
``` # [Python](#tab/python)
+* [SDK reference](/python/api/botbuilder-core/botbuilder.core.turncontext?view=botbuilder-py-latest#botbuilder-core-turncontext-send-activity&preserve-view=true)
+* [Sample code reference](https://github.com/OfficeDev/Microsoft-Teams-Samples/blob/main/samples/bot-conversation/python/bots/teams_conversation_bot.py#L103)
<!-- Verify --> ```python async def on_message_activity(self, turn_context: TurnContext):
+ // Sends a message activity to the sender of the incoming activity.
return await turn_context.send_activity(MessageFactory.text(f"Echo: {turn_context.activity.text}")) ```
The following code shows an example of sending a message when a user is added to
# [C#](#tab/dotnet)
+* [SDK reference](/dotnet/api/microsoft.bot.builder.turncontext.sendactivityasync?view=botbuilder-dotnet-stable#microsoft-bot-builder-turncontext-sendactivityasync(microsoft-bot-schema-iactivity-system-threading-cancellationtoken)&preserve-view=true)
+* [Sample code reference](https://github.com/OfficeDev/Microsoft-Teams-Samples/blob/main/samples/bot-teams-authentication/csharp/Bots/TeamsBot.cs#L29)
+ ```csharp protected override async Task OnMembersAddedAsync(IList<ChannelAccount> membersAdded, ITurnContext<IConversationUpdateActivity> turnContext, CancellationToken cancellationToken) {
+ // Sends an activity to the sender of the incoming activity.
await turnContext.SendActivityAsync(MessageFactory.Text($"Hello and welcome!"), cancellationToken); }
protected override async Task OnMembersAddedAsync(IList<ChannelAccount> membersA
# [TypeScript](#tab/typescript)
-```typescript
+* [Sample code reference](https://github.com/OfficeDev/Microsoft-Teams-Samples/blob/main/samples/bot-conversation/nodejs/bots/teamsConversationBot.js#L46)
+```typescript
this.onMembersAddedActivity(async (context, next) => { await Promise.all((context.activity.membersAdded || []).map(async (member) => { if (member.id !== context.activity.recipient.id) {
+
+ // Sends an activity to the sender of the incoming activity.
await context.sendActivity( `Welcome to the team ${member.givenName} ${member.surname}` );
protected override async Task OnMembersAddedAsync(IList<ChannelAccount> membersA
await next(); });+ ``` # [Python](#tab/python)
+* [SDK reference](/python/api/botbuilder-core/botbuilder.core.activityhandler?view=botbuilder-py-latest#botbuilder-core-activityhandler-on-members-added-activity&preserve-view=true)
+* [Sample code reference](https://github.com/OfficeDev/Microsoft-Teams-Samples/blob/main/samples/bot-teams-authentication/python/bots/auth_bot.py#L26)
<!-- Verify --> ```python- async def on_members_added_activity( self, members_added: [ChannelAccount], turn_context: TurnContext ): for member in teams_members_added:
+ // Sends a message activity to the sender of the incoming activity.
await turn_context.send_activity(f"Welcome your new team member {member.id}") return
The following code shows an example of adding notifications to your message:
# [C#](#tab/dotnet)
+* [SDK reference](/dotnet/api/microsoft.bot.builder.activityhandler.onmessageactivityasync?view=botbuilder-dotnet-stable&preserve-view=true)
+* [Sample code reference](https://github.com/OfficeDev/Microsoft-Teams-Samples/blob/main/samples/meetings-token-app/csharp/Bots/TokenBot.cs#L52)
+ ```csharp protected override async Task OnMessageActivityAsync(ITurnContext<IMessageActivity> turnContext, CancellationToken cancellationToken) {
+ // Returns a simple text message.
var message = MessageFactory.Text("You'll get a notification, if you've turned them on."); message.TeamsNotifyUser();
+ // Sends an activity to the sender of the incoming activity.
await turnContext.SendActivityAsync(message); }+ ``` # [TypeScript](#tab/typescript)
+* [SDK reference](/javascript/api/botbuilder-core/turncontext?view=botbuilder-ts-latest#botbuilder-core-turncontext-sendactivity&preserve-view=true)
+* [Sample code reference](https://github.com/OfficeDev/Microsoft-Teams-Samples/blob/main/samples/app-localization/nodejs/server/bot/botActivityHandler.js#L36)
```typescript+ this.onMessage(async (turnContext, next) => { let message = MessageFactory.text("You'll get a notification, if you've turned them on."); teamsNotifyUser(message);-
+ // Sends an activity to the sender of the incoming activity.
await turnContext.sendActivity(message); // By calling next() you ensure that the next BotHandler is run. await next(); });+ ``` # [Python](#tab/python)
+* [SDK reference](/python/api/botbuilder-core/botbuilder.core.turncontext?view=botbuilder-py-latest#botbuilder-core-turncontext-send-activity&preserve-view=true)
+* [Sample code reference](https://github.com/OfficeDev/Microsoft-Teams-Samples/blob/main/samples/bot-conversation/python/bots/teams_conversation_bot.py#L103)
```python async def on_message_activity(self, turn_context: TurnContext): message = MessageFactory.text("You'll get a notification, if you've turned them on.") teams_notify_user(message)-
+ // Sends an activity to the sender of the incoming activity.
await turn_context.send_activity(message) ```
The general retry guidance for each status code is listed in the following table
## Next step > [!div class="nextstepaction"]
-> [Create a commands menu](../create-a-bot-commands-menu.md)
+> [Bot command menus](~/bots/how-to/create-a-bot-commands-menu.md)
## See also
-* [Build bots for Teams](../../what-are-bots.md)
-* [Bot activity handlers](../../bot-basics.md)
-* [Send proactive messages](send-proactive-messages.md)
+* [Send proactive messages](~/bots/how-to/conversations/send-proactive-messages.md)
* [Subscribe to conversation events](~/bots/how-to/conversations/subscribe-to-conversation-events.md) * [Send and receive files through the bot](~/bots/how-to/bots-filesv4.md)
-* [Send tenant ID and conversation ID to the request headers of the bot](request-headers-of-the-bot.md)
+* [Send tenant ID and conversation ID to the request headers of the bot](~/bots/how-to/conversations/request-headers-of-the-bot.md)
* [Localize your app](../../../concepts/build-and-test/apps-localization.md)
platform Send Proactive Messages https://github.com/MicrosoftDocs/msteams-docs/commits/main/msteams-platform/bots/how-to/conversations/send-proactive-messages.md
See the following video to learn how to send proactive message from bots:
<br>
-> [!VIDEO https://www.microsoft.com/en-us/videoplayer/embed/RE4NHyk]
+> [!VIDEO <https://www.microsoft.com/en-us/videoplayer/embed/RE4NHyk>]
<br> ### Understand who blocked, muted, or uninstalled a bot
The following code shows how to send proactive messages:
# [C#](#tab/dotnet)
+* [SDK reference](/dotnet/api/microsoft.bot.builder.cloudadapterbase.continueconversationasync?view=botbuilder-dotnet-stable#microsoft-bot-builder-cloudadapterbase-continueconversationasync(system-string-microsoft-bot-schema-activity-microsoft-bot-builder-botcallbackhandler-system-threading-cancellationtoken)&preserve-view=true)
+* [Sample code reference](https://github.com/OfficeDev/Microsoft-Teams-Samples/blob/main/samples/graph-meeting-notification/csharp/MeetingNotification/Controllers/NotificationController.cs#L112)
+ ```csharp [Route("api/notify")] [ApiController]
public class NotifyController : ControllerBase
{ foreach (var conversationReference in _conversationReferences.Values) {
+ var newReference = new ConversationReference()
+ {
+ Bot = new ChannelAccount()
+ {
+ Id = conversationReference.Bot.Id
+ },
+ Conversation = new ConversationAccount()
+ {
+ Id = conversationReference.Conversation.Id
+ },
+ ServiceUrl = conversationReference.ServiceUrl,
+ };
+ // Sends a proactive message from the bot to a conversation.
+ await ((BotAdapter)_adapter).ContinueConversationAsync(_appId, newReference, BotCallback, default(CancellationToken));
+= }
- await ((BotAdapter)_adapter).ContinueConversationAsync(_appId, conversationReference, BotCallback, default(CancellationToken));
- }
-
- // Let the caller know proactive messages have been sent
+ // Let the caller know proactive messages have been sent.
return new ContentResult() { Content = "<html><body><h1>Proactive messages have been sent.</h1></body></html>",
public class NotifyController : ControllerBase
{ // If you encounter permission-related errors when sending this message, see // https://aka.ms/BotTrustServiceUrl
+ // Sends an activity to the sender of the incoming activity.
await turnContext.SendActivityAsync("proactive hello"); } }
Example of a code snippet to demonstrate creating conversation reference.
}; # [TypeScript](#tab/typescript)
+* [SDK reference](/javascript/api/botbuilder-core/turncontext?view=botbuilder-ts-latest#botbuilder-core-turncontext-getconversationreference)
+* [Sample code reference](https://github.com/OfficeDev/Microsoft-Teams-Samples/blob/main/samples/graph-proactive-installation/nodejs/bots/proactiveBot.js#L59)
```javascript
async messageAllMembersAsync(context) {
members.forEach(async (teamMember) => { const message = MessageFactory.text('Hello ${ teamMember.givenName } ${ teamMember.surname }. I\'m a Teams conversation bot.');-
+ // A conversation reference for the conversation that contains this activity.
var ref = TurnContext.getConversationReference(context.activity); ref.user = teamMember;
async messageAllMembersAsync(context) {
}); }); });-
+ // Sends an activity to the sender of the incoming activity.
await context.sendActivity(MessageFactory.text('All messages have been sent.')); }+ ``` # [Python](#tab/python)
+* [SDK reference](/python/api/botbuilder-core/botbuilder.core.botadapter?view=botbuilder-py-latest#botbuilder-core-botadapter-continue-conversation&preserve-view=true)
+* [Sample code reference](https://github.com/OfficeDev/Microsoft-Teams-Samples/blob/main/samples/bot-conversation/python/bots/teams_conversation_bot.py#L200)
```python
+# Send message to all members.
async def _message_all_members(self, turn_context: TurnContext): team_members = await self._get_paged_members(turn_context) for member in team_members:
+ # A conversation reference for the conversation that contains this activity.
conversation_reference = TurnContext.get_conversation_reference( turn_context.activity )
async def _message_all_members(self, turn_context: TurnContext):
conversation_reference, get_ref, conversation_parameters )
+ # Sends an activity to the sender of the incoming activity.
await turn_context.send_activity( MessageFactory.text("All messages have been sent") )
async def _message_all_members(self, turn_context: TurnContext):
# [JSON](#tab/json)
+[SDK reference](/microsoftteams/platform/bots/how-to/conversations/send-proactive-messages?tabs=json)
+ ```json POST /v3/conversations {
The following table provides a simple code sample that incorporates basic conver
| Start new thread in a channel | Demonstrates creating a new thread in a channel. | [View](https://github.com/OfficeDev/Microsoft-Teams-Samples/tree/main/samples/bot-initiate-thread-in-channel/csharp) | [View](https://github.com/OfficeDev/Microsoft-Teams-Samples/tree/main/samples/bot-initiate-thread-in-channel/nodejs) | [View](https://github.com/OfficeDev/Microsoft-Teams-Samples/tree/main/samples/bot-initiate-thread-in-channel/python) | | Proactive installation of app and sending proactive notifications | This sample shows how you can use proactive installation of app for users and send proactive notifications by calling Microsoft Graph APIs. | [View](https://github.com/OfficeDev/Microsoft-Teams-Samples/tree/main/samples/graph-proactive-installation/csharp) | [View](https://github.com/OfficeDev/Microsoft-Teams-Samples/tree/main/samples/graph-proactive-installation/nodejs) | NA | | Proactive Messaging | This is a sample that shows how to save user's conversation reference information to send proactive reminder message using Bots. | NA | [View](https://github.com/OfficeDev/Microsoft-Teams-Samples/tree/main/samples/bot-proactive-messaging-teamsfx) | NA |
-| Teams proactive messaging samples | The samples help with building proactive messaging apps in Microsoft Teams getting the conversation coordinates, and sending messages reliably. | [View](https://github.com/OfficeDev/Microsoft-Teams-Samples/tree/main/samples/bot-proactive-messaging/csharp) | NA | NA |
> [!div class="nextstepaction"] > [More code sample of proactive messaging](/samples/officedev/msteams-samples-proactive-messaging/msteams-samples-proactive-messaging/)
The following table provides a simple code sample that incorporates basic conver
## See also
-* [Build bots for Teams](../../what-are-bots.md)
-* [Channel and group chat conversations with a bot](channel-and-group-conversations.md)
-* [Respond to the task module submit action](../../../messaging-extensions/how-to/action-commands/respond-to-task-module-submit.md)
+* [**Teams proactive messaging code samples**](https://github.com/OfficeDev/Microsoft-Teams-Samples/tree/main/samples/bot-proactive-messaging/csharp)
+* [Channel and group chat conversations with a bot](~/bots/how-to/conversations/channel-and-group-conversations.md)
+* [Respond to the task module submit action](~/messaging-extensions/how-to/action-commands/respond-to-task-module-submit.md)
* [Send proactive notifications to users](/azure/bot-service/bot-builder-howto-proactive-message)
-* [Messages in bot conversations](conversation-messages.md)
-* [Build notification bot to send proactive messages](../../../sbs-gs-notificationbot.yml)
+* [Build your first bot app using JavaScript](../../../sbs-gs-bot.yml)
+* [Build notification bot with JavaScript to send a proactive message](../../../sbs-gs-notificationbot.yml)
* [TurnContext](/javascript/api/botbuilder-core/turncontext?view=botbuilder-ts-latest"&preserve-view=true")
platform Subscribe To Conversation Events https://github.com/MicrosoftDocs/msteams-docs/commits/main/msteams-platform/bots/how-to/conversations/subscribe-to-conversation-events.md
The following code shows an example of channel created event:
# [C#](#tab/dotnet)
+* [Sample code reference](https://github.com/OfficeDev/Microsoft-Teams-Samples/blob/main/samples/bot-conversation/csharp/Bots/TeamsConversationBot.cs#L314)
+* [SDK reference](/dotnet/api/microsoft.bot.builder.teams.teamsactivityhandler.onteamschannelcreatedasync?view=botbuilder-dotnet-stable&preserve-view=true)
+ ```csharp protected override async Task OnTeamsChannelCreatedAsync(ChannelInfo channelInfo, TeamInfo teamInfo, ITurnContext<IConversationUpdateActivity> turnContext, CancellationToken cancellationToken) { var heroCard = new HeroCard(text: $"{channelInfo.Name} is the Channel created");
+ // Sends an activity to the sender of the incoming activity.
await turnContext.SendActivityAsync(MessageFactory.Attachment(heroCard.ToAttachment()), cancellationToken); }+ ``` # [TypeScript](#tab/typescript) <!-- From sample: botbuilder-js\libraries\botbuilder\tests\teams\conversationUpdate\src\conversationUpdateBot.ts -->
-```typescript
+* [SDK reference](/javascript/api/botbuilder/teamsactivityhandler?view=botbuilder-ts-latest#botbuilder-teamsactivityhandler-onteamschannelcreatedevent&preserve-view=true)
+```typescript
export class MyBot extends TeamsActivityHandler { constructor() { super(); this.onTeamsChannelCreatedEvent(async (channelInfo: ChannelInfo, teamInfo: TeamInfo, turnContext: TurnContext, next: () => Promise<void>): Promise<void> => { const card = CardFactory.heroCard('Channel Created', `${channelInfo.name} is the Channel created`); const message = MessageFactory.attachment(card);
+ // Sends a message activity to the sender of the incoming activity.
await turnContext.sendActivity(message); await next(); });
export class MyBot extends TeamsActivityHandler {
# [JSON](#tab/json)
+[SDK reference](/microsoftteams/platform/bots/how-to/conversations/subscribe-to-conversation-events?tabs=json#channel-created)
+ ```json { "type": "conversationUpdate",
export class MyBot extends TeamsActivityHandler {
# [Python](#tab/python)
+* [SDK reference](/python/api/botbuilder-core/botbuilder.core.teams.teamsactivityhandler?view=botbuilder-py-latest#botbuilder-core-teams-teamsactivityhandler-on-teams-channel-created&preserve-view=true)
+ ```python async def on_teams_channel_created( self, channel_info: ChannelInfo, team_info: TeamInfo, turn_context: TurnContext ):
+ # Sends a message activity to the sender of the incoming activity.
return await turn_context.send_activity( MessageFactory.text( f"The new channel is {channel_info.name}. The channel id is {channel_info.id}"
The following code shows an example of channel renamed event:
# [C#](#tab/dotnet)
+* [SDK reference](/dotnet/api/microsoft.bot.builder.teams.teamsactivityhandler.onteamschannelrenamedasync?view=botbuilder-dotnet-stable&preserve-view=true)
+* [Sample code reference](https://github.com/OfficeDev/Microsoft-Teams-Samples/blob/main/samples/bot-conversation/csharp/Bots/TeamsConversationBot.cs#L320)
+ ```csharp protected override async Task OnTeamsChannelRenamedAsync(ChannelInfo channelInfo, TeamInfo teamInfo, ITurnContext<IConversationUpdateActivity> turnContext, CancellationToken cancellationToken) { var heroCard = new HeroCard(text: $"{channelInfo.Name} is the new Channel name");
+ // Sends an activity to the sender of the incoming activity.
await turnContext.SendActivityAsync(MessageFactory.Attachment(heroCard.ToAttachment()), cancellationToken); }+ ``` # [TypeScript](#tab/typescript)
+* [SDK reference](/javascript/api/botbuilder/teamsactivityhandler?view=botbuilder-ts-latest#botbuilder-teamsactivityhandler-onteamschannelrenamedevent&preserve-view=true)
+ ```typescript export class MyBot extends TeamsActivityHandler { constructor() {
export class MyBot extends TeamsActivityHandler {
this.onTeamsChannelRenamedEvent(async (channelInfo: ChannelInfo, teamInfo: TeamInfo, turnContext: TurnContext, next: () => Promise<void>): Promise<void> => { const card = CardFactory.heroCard('Channel Renamed', `${channelInfo.name} is the new Channel name`); const message = MessageFactory.attachment(card);
+ // Sends a message activity to the sender of the incoming activity.
await turnContext.sendActivity(message); await next(); });
export class MyBot extends TeamsActivityHandler {
# [JSON](#tab/json)
+[SDK reference](/microsoftteams/platform/bots/how-to/conversations/subscribe-to-conversation-events?tabs=json#channel-renamed)
+ ```json { "type": "conversationUpdate",
export class MyBot extends TeamsActivityHandler {
# [Python](#tab/python)
+* [SDK reference](/python/api/botbuilder-core/botbuilder.core.teams.teamsactivityhandler?view=botbuilder-py-latest#botbuilder-core-teams-teamsactivityhandler-on-teams-channel-renamed&preserve-view=true)
+ ```python async def on_teams_channel_renamed( self, channel_info: ChannelInfo, team_info: TeamInfo, turn_context: TurnContext
The following code shows an example of channel deleted event:
# [C#](#tab/dotnet)
+* [SDK reference](/dotnet/api/microsoft.bot.builder.teams.teamsactivityhandler.onteamschanneldeletedasync?view=botbuilder-dotnet-stable&preserve-view=true)
+* [Sample code reference](https://github.com/OfficeDev/Microsoft-Teams-Samples/blob/main/samples/bot-conversation/csharp/Bots/TeamsConversationBot.cs#L326)
+ ```csharp protected override async Task OnTeamsChannelDeletedAsync(ChannelInfo channelInfo, TeamInfo teamInfo, ITurnContext<IConversationUpdateActivity> turnContext, CancellationToken cancellationToken) { var heroCard = new HeroCard(text: $"{channelInfo.Name} is the Channel deleted"); await turnContext.SendActivityAsync(MessageFactory.Attachment(heroCard.ToAttachment()), cancellationToken); }+ ``` # [TypeScript](#tab/typescript)
+* [SDK reference](/javascript/api/botbuilder/teamsactivityhandler?view=botbuilder-ts-latest#botbuilder-teamsactivityhandler-onteamschanneldeletedevent&preserve-view=true)
+ ```typescript export class MyBot extends TeamsActivityHandler { constructor() {
export class MyBot extends TeamsActivityHandler {
this.onTeamsChannelDeletedEvent(async (channelInfo: ChannelInfo, teamInfo: TeamInfo, turnContext: TurnContext, next: () => Promise<void>): Promise<void> => { const card = CardFactory.heroCard('Channel Deleted', `${channelInfo.name} is the Channel deleted`); const message = MessageFactory.attachment(card);
+ // Sends a message activity to the sender of the incoming activity.
await turnContext.sendActivity(message); await next(); });
export class MyBot extends TeamsActivityHandler {
# [JSON](#tab/json)
+[SDK reference](/microsoftteams/platform/bots/how-to/conversations/subscribe-to-conversation-events?tabs=json#channel-deleted)
+ ```json { "type": "conversationUpdate",
export class MyBot extends TeamsActivityHandler {
# [Python](#tab/python)
+* [SDK reference](/python/api/botbuilder-core/botbuilder.core.teams.teamsactivityhandler?&preserve-view=true)
+ ```python async def on_teams_channel_deleted( self, channel_info: ChannelInfo, team_info: TeamInfo, turn_context: TurnContext ):
+ # Sends a message activity to the sender of the incoming activity.
return await turn_context.send_activity( MessageFactory.text(f"The deleted channel is {channel_info.name}") )
The following code shows an example of channel restored event:
# [C#](#tab/dotnet)
+* [SDK refernce](/dotnet/api/microsoft.bot.builder.teams.teamsactivityhandler.onteamschannelrestoredasync?view=botbuilder-dotnet-stable&preserve-view=true)
+* [Sample code reference](https://github.com/OfficeDev/Microsoft-Teams-Samples/blob/main/samples/msteams-application-qbot/Source/Microsoft.Teams.Apps.QBot.Web/Bot/BotActivityHandler.cs#L395)
+ ```csharp protected override async Task OnTeamsChannelRestoredAsync(ChannelInfo channelInfo, TeamInfo teamInfo, ITurnContext<IConversationUpdateActivity> turnContext, CancellationToken cancellationToken) { var heroCard = new HeroCard(text: $"{channelInfo.Name} is the Channel restored."); await turnContext.SendActivityAsync(MessageFactory.Attachment(heroCard.ToAttachment()), cancellationToken); }+ ``` # [TypeScript](#tab/typescript)
-<!-- From sample: botbuilder-js\libraries\botbuilder\tests\teams\conversationUpdate\src\conversationUpdateBot.ts -->
+* [SDK reference](/javascript/api/botbuilder/teamsactivityhandler?view=botbuilder-ts-latest#botbuilder-teamsactivityhandler-onteamschannelrestoredevent&preserve-view=true)
```typescript
export class MyBot extends TeamsActivityHandler {
this.onTeamsChannelRestoredEvent(async (channelInfo: ChannelInfo, teamInfo: TeamInfo, turnContext: TurnContext, next: () => Promise<void>): Promise<void> => { const card = CardFactory.heroCard('Channel Restored', `${channelInfo.name} is the Channel restored`); const message = MessageFactory.attachment(card);
+ // Sends a message activity to the sender of the incoming activity.
await turnContext.sendActivity(message); await next(); });
export class MyBot extends TeamsActivityHandler {
# [JSON](#tab/json)
+[SDK reference](/microsoftteams/platform/bots/how-to/conversations/subscribe-to-conversation-events?tabs=json#channel-restored)
+ ```json { "type": "conversationUpdate",
export class MyBot extends TeamsActivityHandler {
# [Python](#tab/python)
+* [SDK reference](/python/api/botbuilder-core/botbuilder.core.teams.teamsactivityhandler?view=botbuilder-py-latest#botbuilder-core-teams-teamsactivityhandler-on-teams-channel-restored&preserve-view=true)
+ ```python async def on_teams_channel_restored( self, channel_info: ChannelInfo, team_info: TeamInfo, turn_context: TurnContext ):
+ # Sends a message activity to the sender of the incoming activity.
return await turn_context.send_activity( MessageFactory.text( f"The restored channel is {channel_info.name}. The channel id is {channel_info.id}"
The following code shows an example of team members added event:
# [C#](#tab/dotnet)
+* [SDK reference](/dotnet/api/microsoft.bot.builder.teams.teamsactivityhandler.onteamsmembersaddedasync?view=botbuilder-dotnet-stable&preserve-view=true)
+* [Sample code reference](https://github.com/OfficeDev/Microsoft-Teams-Samples/blob/main/samples/msteams-application-qbot/Source/Microsoft.Teams.Apps.QBot.Web/Bot/BotActivityHandler.cs#L133)
+ ```csharp protected override async Task OnTeamsMembersAddedAsync(IList<TeamsChannelAccount> teamsMembersAdded , TeamInfo teamInfo, ITurnContext<IConversationUpdateActivity> turnContext, CancellationToken cancellationToken) {
protected override async Task OnTeamsMembersAddedAsync(IList<TeamsChannelAccount
{ if (member.Id == turnContext.Activity.Recipient.Id) {
- // Send a message to introduce the bot to the team
+ // Send a message to introduce the bot to the team.
var heroCard = new HeroCard(text: $"The {member.Name} bot has joined {teamInfo.Name}");
+ // Sends an activity to the sender of the incoming activity.
await turnContext.SendActivityAsync(MessageFactory.Attachment(heroCard.ToAttachment()), cancellationToken); } else { var heroCard = new HeroCard(text: $"{member.Name} joined {teamInfo.Name}");
+ // Sends an activity to the sender of the incoming activity.
await turnContext.SendActivityAsync(MessageFactory.Attachment(heroCard.ToAttachment()), cancellationToken); } } }+ ``` # [TypeScript](#tab/typescript)
+* [SDK reference](/javascript/api/botbuilder/teamsactivityhandler?view=botbuilder-ts-latest#botbuilder-teamsactivityhandler-onteamsmembersaddedevent&preserve-view=true)
+ ```typescript export class MyBot extends TeamsActivityHandler { constructor() {
export class MyBot extends TeamsActivityHandler {
const name = !teamInfo ? 'not in team' : teamInfo.name; const card = CardFactory.heroCard('Account Added', `${newMembers} joined ${name}.`); const message = MessageFactory.attachment(card);
+ // Sends a message activity to the sender of the incoming activity.
await turnContext.sendActivity(message); await next(); });
export class MyBot extends TeamsActivityHandler {
# [JSON](#tab/json)
+[SDK reference](/microsoftteams/platform/bots/how-to/conversations/subscribe-to-conversation-events?tabs=json#members-added)
+ The message your bot receives when the bot is added to a team. > [!NOTE]
The message your bot receives when the bot is added to a one-to-one chat.
# [Python](#tab/python)
+* [SDK reference](/python/api/botbuilder-core/botbuilder.core.teams.teamsactivityhandler?view=botbuilder-py-latest#botbuilder-core-teams-teamsactivityhandler-on-teams-members-added&preserve-view=true)
+ ```python async def on_teams_members_added( self, teams_members_added: [TeamsChannelAccount], turn_context: TurnContext ): for member in teams_members_added:
+.. # Sends a message activity to the sender of the incoming activity.
await turn_context.send_activity( MessageFactory.text(f"Welcome your new team member {member.id}") )
The following code shows an example of team members removed event:
# [C#](#tab/dotnet)
+* [SDK reference](/dotnet/api/microsoft.bot.builder.teams.teamsactivityhandler.onteamsmembersremovedasync?view=botbuilder-dotnet-stable&preserve-view=true)
+* [Sample code reference](https://github.com/OfficeDev/Microsoft-Teams-Samples/blob/main/samples/msteams-application-qbot/Source/Microsoft.Teams.Apps.QBot.Web/Bot/BotActivityHandler.cs#L157)
+ ```csharp protected override async Task OnTeamsMembersRemovedAsync(IList<ChannelAccount> membersRemoved, TeamInfo teamInfo, ITurnContext<IConversationUpdateActivity> turnContext, CancellationToken cancellationToken) {
protected override async Task OnTeamsMembersRemovedAsync(IList<ChannelAccount> m
{ if (member.Id == turnContext.Activity.Recipient.Id) {
- // The bot was removed
- // You should clear any cached data you have for this team
+ // The bot was removed.
+ // You should clear any cached data you have for this team.
} else { var heroCard = new HeroCard(text: $"{member.Name} was removed from {teamInfo.Name}");
+ // Sends an activity to the sender of the incoming activity.
await turnContext.SendActivityAsync(MessageFactory.Attachment(heroCard.ToAttachment()), cancellationToken); } } }+ ``` # [TypeScript](#tab/typescript)
-```typescript
+* [SDK reference](/javascript/api/botbuilder/teamsactivityhandler?view=botbuilder-ts-latest#botbuilder-teamsactivityhandler-onteamsmembersaddedevent&preserve-view=true)
+```typescript
export class MyBot extends TeamsActivityHandler { constructor() { super();
export class MyBot extends TeamsActivityHandler {
const name = !teamInfo ? 'not in team' : teamInfo.name; const card = CardFactory.heroCard('Account Removed', `${removedMembers} removed from ${teamInfo.name}.`); const message = MessageFactory.attachment(card);
+ // Sends a message activity to the sender of the incoming activity.
await turnContext.sendActivity(message); await next(); });
export class MyBot extends TeamsActivityHandler {
# [JSON](#tab/json)
+[SDK reference](/microsoftteams/platform/bots/how-to/conversations/subscribe-to-conversation-events?tabs=json#members-removed)
+ The `channelData` object in the following payload example is based on adding a member to a team rather than a group chat, or initiating a new one-to-one conversation: ```json
The `channelData` object in the following payload example is based on adding a m
# [Python](#tab/python)
+* [SDK reference](/python/api/botbuilder-core/botbuilder.core.teams.teamsactivityhandler?view=botbuilder-py-latest#botbuilder-core-teams-teamsactivityhandler-on-teams-members-removed&preserve-view=true)
+ ```python async def on_teams_members_removed( self, teams_members_removed: [TeamsChannelAccount], turn_context: TurnContext ): for member in teams_members_removed:
+..# Sends a message activity to the sender of the incoming activity.
await turn_context.send_activity( MessageFactory.text(f"Say goodbye to {member.id}") )
The following code shows an example of team renamed event:
# [C#](#tab/dotnet)
+* [SDK reference](/dotnet/api/microsoft.bot.builder.teams.teamsactivityhandler.onteamsteamrenamedasync?view=botbuilder-dotnet-stable#definition&preserve-view=true)
+* [Sample code reference](https://github.com/OfficeDev/Microsoft-Teams-Samples/blob/main/samples/bot-conversation/csharp/Bots/TeamsConversationBot.cs#L320)
+ ```csharp protected override async Task OnTeamsTeamRenamedAsync(TeamInfo teamInfo, ITurnContext<IConversationUpdateActivity> turnContext, CancellationToken cancellationToken) { var heroCard = new HeroCard(text: $"{teamInfo.Name} is the new Team name");
+ // Sends an activity to the sender of the incoming activity.
await turnContext.SendActivityAsync(MessageFactory.Attachment(heroCard.ToAttachment()), cancellationToken); } ``` # [TypeScript](#tab/typescript)
+* [SDK reference](/javascript/api/botbuilder/teamsactivityhandler?view=botbuilder-ts-latest#botbuilder-teamsactivityhandler-onteamsteamrenamedevent&preserve-view=true)
+ ```typescript export class MyBot extends TeamsActivityHandler { constructor() { super();
+ // Bot is notified when the team is renamed.
this.onTeamsTeamRenamedEvent(async (teamInfo: TeamInfo, turnContext: TurnContext, next: () => Promise<void>): Promise<void> => { const card = CardFactory.heroCard('Team Renamed', `${teamInfo.name} is the new Team name`); const message = MessageFactory.attachment(card);+
+ // Sends an activity to the sender of the incoming activity.
await turnContext.sendActivity(message); await next(); });
export class MyBot extends TeamsActivityHandler {
# [JSON](#tab/json)
+* [SDK reference](/microsoftteams/platform/bots/how-to/conversations/subscribe-to-conversation-events?tabs=json#team-renamed)
+ ```json { "type": "conversationUpdate",
export class MyBot extends TeamsActivityHandler {
# [Python](#tab/python)
+* [SDK reference](/python/api/botbuilder-core/botbuilder.core.teams.teamsactivityhandler?view=botbuilder-py-latest#botbuilder-core-teams-teamsactivityhandler-on-teams-team-renamed&preserve-view=true)
+ ```python
+# Bot is notified when the team is renamed.
async def on_teams_team_renamed( self, team_info: TeamInfo, turn_context: TurnContext ):
+ # Sends an activity to the sender of the incoming activity.
return await turn_context.send_activity( MessageFactory.text(f"The new team name is {team_info.name}") )
The following code shows an example of team deleted event:
# [C#](#tab/dotnet)
+* [SDK reference](/dotnet/api/microsoft.bot.builder.teams.teamsactivityhandler.onteamsteamdeletedasync?view=botbuilder-dotnet-stable#definition&preserve-view=true)
+ ```csharp protected override async Task OnTeamsTeamDeletedAsync(TeamInfo teamInfo, ITurnContext<IConversationUpdateActivity> turnContext, CancellationToken cancellationToken) {
- //handle delete event
+ // Handle delete event.
} ``` # [TypeScript](#tab/typescript)
+* [SDK reference](/javascript/api/botbuilder/teamsactivityhandler?view=botbuilder-ts-latest#botbuilder-teamsactivityhandler-onteamsteamdeletedevent&preserve-view=true)
```typescript export class MyBot extends TeamsActivityHandler { constructor() { super();
+ // Invoked when a Team Deleted event activity is received from the connector. Team Deleted corresponds to the user deleting a team.
this.onTeamsTeamDeletedEvent(async (teamInfo: TeamInfo, turnContext: TurnContext, next: () => Promise<void>): Promise<void> => {
- //handle delete event
+ // Handle delete event.
await next(); }); }
export class MyBot extends TeamsActivityHandler {
# [JSON](#tab/json)
+* [SDK reference](/microsoftteams/platform/bots/how-to/conversations/subscribe-to-conversation-events?tabs=json#team-deleted)
+ ```json { "type": "conversationUpdate",
export class MyBot extends TeamsActivityHandler {
``` # [Python](#tab/python)
+* [SDK reference](/python/api/botbuilder-core/botbuilder.core.teams.teamsactivityhandler?view=botbuilder-py-latest#botbuilder-core-teams-teamsactivityhandler-on-teams-team-deleted&preserve-view=true)
```python
+# Invoked when a Team Deleted event activity is received from the connector. Team Deleted corresponds to the user deleting a team.
async def on_teams_team_deleted( self, team_info: TeamInfo, turn_context: TurnContext ):
- //handle delete event
+ # Handle delete event.
) ```
The following code shows an example of team restored event:
# [C#](#tab/dotnet)
+* [SDK reference](/dotnet/api/microsoft.bot.builder.teams.teamsactivityhandler.onteamsteamrestoredasync?view=botbuilder-dotnet-stable#definition&preserve-view=true)
+ ```csharp protected override async Task OnTeamsTeamrestoredAsync(TeamInfo teamInfo, ITurnContext<IConversationUpdateActivity> turnContext, CancellationToken cancellationToken) { var heroCard = new HeroCard(text: $"{teamInfo.Name} is the team name");
+ // Sends an activity to the sender of the incoming activity.
await turnContext.SendActivityAsync(MessageFactory.Attachment(heroCard.ToAttachment()), cancellationToken); } ``` # [TypeScript](#tab/typescript)
+* [SDK reference](/javascript/api/botbuilder/teamsactivityhandler?view=botbuilder-ts-latest#botbuilder-teamsactivityhandler-onteamsteamrestoredevent&preserve-view=true)
+ ```typescript export class MyBot extends TeamsActivityHandler { constructor() { super();
+ // Invoked when a Team Restored event activity is received from the connector. Team Restored corresponds to the user restoring a team.
this.onTeamsTeamrestoredEvent(async (teamInfo: TeamInfo, turnContext: TurnContext, next: () => Promise<void>): Promise<void> => { const card = CardFactory.heroCard('Team restored', `${teamInfo.name} is the team name`); const message = MessageFactory.attachment(card);
+ // Sends an activity to the sender of the incoming activity.
await turnContext.sendActivity(message); await next(); });
export class MyBot extends TeamsActivityHandler {
# [JSON](#tab/json)
+* [SDK reference](/microsoftteams/platform/bots/how-to/conversations/subscribe-to-conversation-events?tabs=json#team-restored)
+ ```json { "type": "conversationUpdate",
export class MyBot extends TeamsActivityHandler {
# [Python](#tab/python)
+* [SDK reference](/python/api/botbuilder-core/botbuilder.core.teams.teamsactivityhandler?view=botbuilder-py-latest#botbuilder-core-teams-teamsactivityhandler-on-teams-team-restored&preserve-view=true)
+ ```python
+# Invoked when a Team Restored event activity is received from the connector. Team Restored corresponds to the user restoring a team.
async def on_teams_team_restored( self, team_info: TeamInfo, turn_context: TurnContext ):
+ # Sends an activity to the sender of the incoming activity.
return await turn_context.send_activity( MessageFactory.text(f"The team name is {team_info.name}") )
The following code shows an example of team archived event:
# [C#](#tab/dotnet)
+* [SDK reference](/dotnet/api/microsoft.bot.builder.teams.teamsactivityhandler.onteamsteamarchivedasync?view=botbuilder-dotnet-stable#definition&preserve-view=true)
+ ```csharp protected override async Task OnTeamsTeamArchivedAsync(TeamInfo teamInfo, ITurnContext<IConversationUpdateActivity> turnContext, CancellationToken cancellationToken) { var heroCard = new HeroCard(text: $"{teamInfo.Name} is the team name");
+ // Sends an activity to the sender of the incoming activity.
await turnContext.SendActivityAsync(MessageFactory.Attachment(heroCard.ToAttachment()), cancellationToken); } ``` # [TypeScript](#tab/typescript)
+* [SDK reference](/javascript/api/botbuilder/teamsactivityhandler?view=botbuilder-ts-latest#botbuilder-teamsactivityhandler-onteamsteamarchivedevent&preserve-view=true)
+ ```typescript export class MyBot extends TeamsActivityHandler { constructor() { super();
+ // Invoked when a Team Archived event activity is received from the connector. Team Archived.
this.onTeamsTeamArchivedEvent(async (teamInfo: TeamInfo, turnContext: TurnContext, next: () => Promise<void>): Promise<void> => { const card = CardFactory.heroCard('Team archived', `${teamInfo.name} is the team name`); const message = MessageFactory.attachment(card);
+ // Sends an activity to the sender of the incoming activity.
await turnContext.sendActivity(message); await next(); });
export class MyBot extends TeamsActivityHandler {
# [JSON](#tab/json)
+* [SDK reference](/microsoftteams/platform/bots/how-to/conversations/subscribe-to-conversation-events?tabs=json#team-archived)
+ ```json { "type": "conversationUpdate",
export class MyBot extends TeamsActivityHandler {
# [Python](#tab/python)
+* [SDK reference](/python/api/botbuilder-core/botbuilder.core.teams.teamsactivityhandler?view=botbuilder-py-latest#botbuilder-core-teams-teamsactivityhandler-on-teams-team-archived&preserve-view=true)
+ ```python
+# Invoked when a Team Archived event activity is received from the connector. Team Archived correspond to the user archiving a team.
async def on_teams_team_archived( self, team_info: TeamInfo, turn_context: TurnContext ):
+ # Sends an activity to the sender of the incoming activity.
return await turn_context.send_activity( MessageFactory.text(f"The team name is {team_info.name}") )
The following code shows an example of team unarchived event:
# [C#](#tab/dotnet)
+* [SDK reference](/dotnet/api/microsoft.bot.builder.teams.teamsactivityhandler.onteamsteamunarchivedasync?view=botbuilder-dotnet-stable#definition&preserve-view=true)
+ ```csharp protected override async Task OnTeamsTeamUnarchivedAsync(TeamInfo teamInfo, ITurnContext<IConversationUpdateActivity> turnContext, CancellationToken cancellationToken) { var heroCard = new HeroCard(text: $"{teamInfo.Name} is the team name");
+ // Sends an activity to the sender of the incoming activity.
await turnContext.SendActivityAsync(MessageFactory.Attachment(heroCard.ToAttachment()), cancellationToken); } ``` # [TypeScript](#tab/typescript)
+* [SDK reference](/javascript/api/botbuilder/teamsactivityhandler?view=botbuilder-ts-latest#botbuilder-teamsactivityhandler-onteamsteamunarchivedevent&preserve-view=true)
+ ```typescript export class MyBot extends TeamsActivityHandler { constructor() { super();
+ // Invoked when a Team Unarchived event activity is received from the connector. Team.
this.onTeamsTeamUnarchivedEvent(async (teamInfo: TeamInfo, turnContext: TurnContext, next: () => Promise<void>): Promise<void> => { const card = CardFactory.heroCard('Team archived', `${teamInfo.name} is the team name`); const message = MessageFactory.attachment(card);
+ // Sends an activity to the sender of the incoming activity.
await turnContext.sendActivity(message); await next(); });
export class MyBot extends TeamsActivityHandler {
# [JSON](#tab/json)
+* [SDK reference](/microsoftteams/platform/bots/how-to/conversations/subscribe-to-conversation-events?tabs=json#team-unarchived)
+ ```json { "type": "conversationUpdate",
export class MyBot extends TeamsActivityHandler {
``` # [Python](#tab/python)
+* [SDK reference](/python/api/botbuilder-core/botbuilder.core.teams.teamsactivityhandler?view=botbuilder-py-latest#botbuilder-core-teams-teamsactivityhandler-on-teams-team-unarchived&preserve-view=true)
```python
+# Invoked when a Team Unarchived event activity is received from the connector. Team Unarchived correspond to the user unarchiving a team.
async def on_teams_team_unarchived( self, team_info: TeamInfo, turn_context: TurnContext ):
+# Sends an activity to the sender of the incoming activity.
return await turn_context.send_activity( MessageFactory.text(f"The team name is {team_info.name}") )
The following code shows an example of reactions to a bot message:
# [C#](#tab/dotnet)
+* [SDK reference](/dotnet/api/microsoft.bot.builder.activityhandler.onreactionsaddedasync?view=botbuilder-dotnet-stable#definition&preserve-view=true)
+* [Sample code reference](https://github.com/OfficeDev/Microsoft-Teams-Samples/blob/main/samples/bot-message-reaction/csharp/Bots/MessageReactionBot.cs#L26)
+ ```csharp protected override async Task OnReactionsAddedAsync(IList<MessageReaction> messageReactions, ITurnContext<IMessageReactionActivity> turnContext, CancellationToken cancellationToken) {
protected override async Task OnReactionsAddedAsync(IList<MessageReaction> messa
{ var newReaction = $"You reacted with '{reaction.Type}' to the following message: '{turnContext.Activity.ReplyToId}'"; var replyActivity = MessageFactory.Text(newReaction);
+ // Sends an activity to the sender of the incoming activity.
var resourceResponse = await turnContext.SendActivityAsync(replyActivity, cancellationToken); } }
protected override async Task OnReactionsAddedAsync(IList<MessageReaction> messa
# [TypeScript](#tab/typescript)
+* [Sample code reference](https://github.com/OfficeDev/Microsoft-Teams-Samples/blob/main/samples/bot-conversation/nodejs/bots/teamsConversationBot.js#L55)
+ <!-- Verify --> ```typescript
protected override async Task OnReactionsAddedAsync(IList<MessageReaction> messa
export class MyBot extends TeamsActivityHandler { constructor() { super();
+ // Override this in a derived class to provide logic for when reactions to a previous activity.
this.onReactionsAdded(async (context, next) => { const reactionsAdded = context.activity.reactionsAdded; if (reactionsAdded && reactionsAdded.length > 0) { for (let i = 0; i < reactionsAdded.length; i++) { const reaction = reactionsAdded[i]; const newReaction = `You reacted with '${reaction.type}' to the following message: '${context.activity.replyToId}'`;
+ // Sends an activity to the sender of the incoming activity.
const resourceResponse = context.sendActivity(newReaction); // Save information about the sent message and its ID (resourceResponse.id). }
export class MyBot extends TeamsActivityHandler {
}); } }- ``` # [JSON](#tab/json)
+* [SDK reference](/microsoftteams/platform/bots/how-to/conversations/subscribe-to-conversation-events?tabs=json#reactions-added-to-bot-message)
+ ```json { "reactionsAdded": [
export class MyBot extends TeamsActivityHandler {
# [Python](#tab/python)
+* [SDK reference](/python/api/botbuilder-core/botbuilder.core.activityhandler?view=botbuilder-py-latest#botbuilder-core-activityhandler-on-reactions-added&preserve-view=true)
+ ```python
+# Override this in a derived class to provide logic for when reactions to a previous activity are added to the conversation.
async def on_reactions_added( self, message_reactions: List[MessageReaction], turn_context: TurnContext ): for reaction in message_reactions: activity = await self._log.find(turn_context.activity.reply_to_id) if not activity:
+ # Sends an activity to the sender of the incoming activity.
await self._send_message_and_log_activity_id( turn_context, f"Activity {turn_context.activity.reply_to_id} not found in log", ) else:
+ # Sends an activity to the sender of the incoming activity.
await self._send_message_and_log_activity_id( turn_context, f"You added '{reaction.type}' regarding '{activity.text}'",
The following code shows an example of reactions removed from bot message:
# [C#](#tab/dotnet)
+* [SDK reference](/dotnet/api/microsoft.bot.builder.activityhandler.onreactionsremovedasync?view=botbuilder-dotnet-stable#definition&preserve-view=true)
+* [Sample code reference](https://github.com/OfficeDev/Microsoft-Teams-Samples/blob/main/samples/bot-message-reaction/csharp/Bots/MessageReactionBot.cs#L44)
+ ```csharp protected override async Task OnReactionsRemovedAsync(IList<MessageReaction> messageReactions, ITurnContext<IMessageReactionActivity> turnContext, CancellationToken cancellationToken) { foreach (var reaction in messageReactions) { var newReaction = $"You removed the reaction '{reaction.Type}' from the following message: '{turnContext.Activity.ReplyToId}'";+ var replyActivity = MessageFactory.Text(newReaction);
+ // Sends an activity to the sender of the incoming activity.
var resourceResponse = await turnContext.SendActivityAsync(replyActivity, cancellationToken); } }
protected override async Task OnReactionsRemovedAsync(IList<MessageReaction> mes
# [TypeScript](#tab/typescript)
+* [Sample code reference](https://github.com/OfficeDev/Microsoft-Teams-Samples/blob/main/samples/bot-conversation/nodejs/bots/teamsConversationBot.js#L63)
+ <!-- Verify --> ```typescript export class MyBot extends TeamsActivityHandler { constructor() { super();
+ // Override this in a derived class to provide logic for when reactions to a previous activity.
this.onReactionsRemoved(async(context,next)=>{ const reactionsRemoved = context.activity.reactionsRemoved; if (reactionsRemoved && reactionsRemoved.length > 0) { for (let i = 0; i < reactionsRemoved.length; i++) { const reaction = reactionsRemoved[i]; const newReaction = `You removed the reaction '${reaction.type}' from the message: '${context.activity.replyToId}'`;
+ // Sends an activity to the sender of the incoming activity.
const resourceResponse = context.sendActivity(newReaction); // Save information about the sent message and its ID (resourceResponse.id). }
export class MyBot extends TeamsActivityHandler {
# [JSON](#tab/json)
+* [SDK reference](/microsoftteams/platform/bots/how-to/conversations/subscribe-to-conversation-events?tabs=json#reactions-removed-from-bot-message)
+ ```json { "reactionsRemoved": [
export class MyBot extends TeamsActivityHandler {
``` # [Python](#tab/python)
+* [SDK reference](/python/api/botbuilder-core/botbuilder.core.activityhandler?view=botbuilder-py-latest#botbuilder-core-activityhandler-on-reactions-removed&preserve-view=true)
```python
+# Override this in a derived class to provide logic specific to removed activities.
async def on_reactions_removed( self, message_reactions: List[MessageReaction], turn_context: TurnContext ): for reaction in message_reactions: activity = await self._log.find(turn_context.activity.reply_to_id) if not activity:
+ # Sends an activity to the sender of the incoming activity.
await self._send_message_and_log_activity_id( turn_context, f"Activity {turn_context.activity.reply_to_id} not found in log", ) else:
+ # Sends an activity to the sender of the incoming activity.
await self._send_message_and_log_activity_id( turn_context, f"You removed '{reaction.type}' regarding '{activity.text}'",
In this example, the `conversation.id` of the `conversationUpdate` and `installa
# [C#](#tab/dotnet)
+* [SDK reference](/dotnet/api/microsoft.bot.builder.cloudadapterbase.continueconversationasync?view=botbuilder-dotnet-stable#microsoft-bot-builder-cloudadapterbase-continueconversationasync(system-string-microsoft-bot-schema-activity-microsoft-bot-builder-botcallbackhandler-system-threading-cancellationtoken)&preserve-view=true)
+* [Sample code reference](https://github.com/OfficeDev/Microsoft-Teams-Samples/blob/main/samples/bot-conversation/csharp/Bots/TeamsConversationBot.cs#L70-L80)
+ ```csharp protected override async Task OnInstallationUpdateActivityAsync(ITurnContext<IInstallationUpdateActivity> turnContext, CancellationToken cancellationToken) { var activity = turnContext.Activity; if (string.Equals(activity.Action, "Add", StringComparison.InvariantCultureIgnoreCase)) {
- // TO:DO Installation workflow
+ // TO:DO Installation workflow.
} else {
- // TO:DO Uninstallation workflow
+ // TO:DO Uninstallation workflow.
} return; }
protected override async Task OnInstallationUpdateAddAsync(ITurnContext<IInstall
# [TypeScript](#tab/typescript)
+* [Sample code reference](https://github.com/OfficeDev/Microsoft-Teams-Samples/blob/main/samples/bot-conversation/nodejs/bots/teamsConversationBot.js#L72-L78)
+ ```typescript async onInstallationUpdateActivity(context: TurnContext) { var activity = context.activity.action; if(activity == "Add") {
+ // Sends an activity to the sender of the incoming activity to add.
await context.sendActivity(MessageFactory.text("Added")); } else {
+ // Sends an activity to the sender of the incoming activity to uninstalled.
await context.sendActivity(MessageFactory.text("Uninstalled")); } }
async onInstallationUpdateActivity(context: TurnContext) {
# [JSON](#tab/json)
+* [SDK reference](/microsoftteams/platform/bots/how-to/conversations/subscribe-to-conversation-events?tabs=json#install-update-event)
+ ```json { {
async onInstallationUpdateActivity(context: TurnContext) {
# [Python](#tab/python)
+* [SDK reference](/python/api/botbuilder-core/botbuilder.core.activityhandler?view=botbuilder-py-latest#botbuilder-core-activityhandler-on-installation-update&preserve-view=true)
+ ```python
+# Override this in a derived class to provide logic specific to InstallationUpdate activities.
async def on_installation_update(self, turn_context: TurnContext):
- if turn_context.activity.action == "add":
+ if turn_context.activity.action == "add":
+ # Sends an activity to the sender of the incoming activity to add.
await turn_context.send_activity(MessageFactory.text("Added")) else:
+ # Sends an activity to the sender of the incoming activity to uninstalled.
await turn_context.send_activity(MessageFactory.text("Uninstalled")) ```
platform Create A Bot Commands Menu https://github.com/MicrosoftDocs/msteams-docs/commits/main/msteams-platform/bots/how-to/create-a-bot-commands-menu.md
Bots in a group or channel respond only when they are mentioned `@botname` in a
# [C#](#tab/dotnet)
+* [SDK reference](/dotnet/api/microsoft.bot.schema.activityextensions.removerecipientmention?view=botbuilder-dotnet-stable#microsoft-bot-schema-activityextensions-removerecipientmention(microsoft-bot-schema-imessageactivity)&preserve-view=true)
+* [Sample code reference](https://github.com/OfficeDev/Microsoft-Teams-Samples/blob/main/samples/app-hello-world/csharp/Microsoft.Teams.Samples.HelloWorld.Web/Bots/MessageExtension.cs#L19)
+ You can parse out the **\@Mention** portion of the message text using a static method provided with the Microsoft Bot Framework. It is a method of the `Activity` class named `RemoveRecipientMention`. The C# code to parse out the **\@Mention** portion of the message text is as follows: ```csharp
+// Remove recipient mention text from Text property.
+// Use with caution because this function is altering the text on the Activity.
var modifiedText = turnContext.Activity.RemoveRecipientMention(); ``` # [JavaScript](#tab/javascript)
+* [SDK reference](/javascript/api/botbuilder-core/turncontext?view=botbuilder-ts-latest#botbuilder-core-turncontext-removementiontext&preserve-view=true)
+* [Sample code reference](https://github.com/OfficeDev/Microsoft-Teams-Samples/blob/main/samples/bot-people-picker-adaptive-card/nodejs/bots/teamsBot.js#L21)
+ You can parse out the **\@Mention** portion of the message text using a static method provided with the Bot Framework. It is a method of the `TurnContext` class named `removeMentionText`. The JavaScript code to parse out the **\@Mention** portion of the message text is as follows: ```javascript
+// Remove mention text from Text property, this function is altering the text on the Activity.
const modifiedText = TurnContext.removeMentionText(turnContext.activity, turnContext.activity.recipient.id); ``` # [Python](#tab/python)
+* [SDK reference](/python/api/botbuilder-core/botbuilder.core.turncontext?view=botbuilder-py-latest#botbuilder-core-turncontext-remove-recipient-mention&preserve-view=true)
+* [Sample code reference](https://github.com/OfficeDev/Microsoft-Teams-Samples/blob/main/samples/bot-conversation/python/bots/teams_conversation_bot.py#L34)
+ You can parse out the **@Mention** portion of the message text using a static method provided with the Bot Framework. It is a method of the `TurnContext` class named `remove_recipient_mention`. The Python code to parse out the **\@Mention** portion of the message text is as follows: ```python
+# Remove recipient mention text from Text property, this function is altering the text on the Activity.
modified_text = TurnContext.remove_recipient_mention(turn_context.activity) ```
platform Get Teams Context https://github.com/MicrosoftDocs/msteams-docs/commits/main/msteams-platform/bots/how-to/get-teams-context.md
The following sample code uses the paged endpoint for fetching the roster:
# [C#](#tab/dotnet)
+* [SDK reference](/dotnet/api/microsoft.bot.builder.teams.teamsinfo.getpagedmembersasync?view=botbuilder-dotnet-stable#microsoft-bot-builder-teams-teamsinfo-getpagedmembersasync(microsoft-bot-builder-iturncontext-system-nullable((system-int32))-system-string-system-threading-cancellationtoken)&preserve-view=true)
+* [Sample code reference](https://github.com/OfficeDev/Microsoft-Teams-Samples/blob/main/samples/graph-proactive-installation/csharp/ProactiveAppInstallation/Bots/ProactiveBot.cs#L78)
+ ```csharp public class MyBot : TeamsActivityHandler {
public class MyBot : TeamsActivityHandler
string continuationToken = null; do
- {
+ {
+ // Gets a paginated list of members of one-on-one, group, or team conversation.
var currentPage = await TeamsInfo.GetPagedMembersAsync(turnContext, 100, continuationToken, cancellationToken); continuationToken = currentPage.ContinuationToken; members.AddRange(currentPage.Members);
public class MyBot : TeamsActivityHandler
# [TypeScript](#tab/typescript)
+* [SDK reference](/javascript/api/botbuilder/teamsinfo?view=botbuilder-ts-latest#botbuilder-teamsinfo-getpagedmembers&preserve-view=true)
+* [Sample code reference](https://github.com/OfficeDev/Microsoft-Teams-Samples/blob/main/samples/graph-proactive-installation/nodejs/bots/proactiveBot.js#L38)
+ ```typescript export class MyBot extends TeamsActivityHandler { constructor() {
export class MyBot extends TeamsActivityHandler {
var members = []; do {
+ // Gets a paginated list of members of one-on-one, group, or team conversation.
var pagedMembers = await TeamsInfo.getPagedMembers(turnContext, 100, continuationToken); continuationToken = pagedMembers.continuationToken; members.push(...pagedMembers.members);
export class MyBot extends TeamsActivityHandler {
``` # [Python](#tab/python)
+* [SDK reference](/python/api/botbuilder-core/botbuilder.core.teams.teamsinfo?view=botbuilder-py-latest#botbuilder-core-teams-teamsinfo-get-team-members&preserve-view=true)
```python async def _show_members( self, turn_context: TurnContext ):
+ # Get a conversationMember from a team.
members = await TeamsInfo.get_team_members(turn_context) ```
The following sample code is used to get single member details:
# [C#](#tab/dotnet)
+* [SDK reference](/dotnet/api/microsoft.bot.builder.teams.teamsinfo.getmemberasync?view=botbuilder-dotnet-stable#microsoft-bot-builder-teams-teamsinfo-getmemberasync(microsoft-bot-builder-iturncontext-system-string-system-threading-cancellationtoken)&preserve-view=true)
+* [Sample code reference](https://github.com/OfficeDev/Microsoft-Teams-Samples/blob/main/samples/bot-sequential-flow-adaptive-cards/csharp/SequentialUserSpecificFlow/Bots/UserSpecificBot.cs#L37)
+ ```csharp public class MyBot : TeamsActivityHandler { protected override async Task OnMessageActivityAsync(ITurnContext<IMessageActivity> turnContext, CancellationToken cancellationToken)
- {
+ {
+ // Gets the account of a single conversation member.
+ // This works in one-on-one, group, and team scoped conversations.
var member = await TeamsInfo.GetMemberAsync(turnContext, turnContext.Activity.From.Id, cancellationToken); } }
public class MyBot : TeamsActivityHandler
# [TypeScript](#tab/typescript)
+* [SDK reference](/javascript/api/botbuilder/teamsinfo?view=botbuilder-ts-latest#botbuilder-teamsinfo-getmember&preserve-view=true)
+* [Sample code reference](https://github.com/OfficeDev/Microsoft-Teams-Samples/blob/main/samples/bot-conversation/nodejs/bots/teamsConversationBot.js#L157)
+ ```typescript export class MyBot extends TeamsActivityHandler { constructor() {
export class MyBot extends TeamsActivityHandler {
# [Python](#tab/python)
+* [SDK reference](/python/api/botbuilder-core/botbuilder.core.teams.teamsinfo?view=botbuilder-py-latest#botbuilder-core-teams-teamsinfo-get-member&preserve-view=true)
+* [Sample code reference](https://github.com/OfficeDev/Microsoft-Teams-Samples/blob/main/samples/bot-conversation/python/bots/teams_conversation_bot.py#L67)
+ ```python async def _show_members( self, turn_context: TurnContext ):
+ # TeamsInfo.get_member: Gets the member of a team scoped conversation.
member = await TeamsInfo.get_member(turn_context, turn_context.activity.from_property.id) ```
The following sample code is used to get team's details:
# [C#](#tab/dotnet)
+* [SDK reference](/dotnet/api/microsoft.bot.builder.teams.teamsinfo.getteamdetailsasync?view=botbuilder-dotnet-stable#microsoft-bot-builder-teams-teamsinfo-getteamdetailsasync(microsoft-bot-builder-iturncontext-system-string-system-threading-cancellationtoken)&preserve-view=true)
+* [Sample code reference](https://github.com/OfficeDev/Microsoft-Teams-Samples/blob/main/samples/msteams-application-qbot/Source/Microsoft.Teams.Apps.QBot.Web/Bot/QBotTeamInfo.cs#L44)
+ ```csharp public class MyBot : TeamsActivityHandler { protected override async Task OnMessageActivityAsync(ITurnContext<IMessageActivity> turnContext, CancellationToken cancellationToken) {
+ // Gets the details for the given team id. This only works in team scoped conversations.
+ // TeamsGetTeamInfo: Gets the TeamsInfo object from the current activity.
TeamDetails teamDetails = await TeamsInfo.GetTeamDetailsAsync(turnContext, turnContext.Activity.TeamsGetTeamInfo().Id, cancellationToken); if (teamDetails != null) { await turnContext.SendActivityAsync($"The groupId is: {teamDetails.AadGroupId}"); } else {
+ // Sends a message activity to the sender of the incoming activity.
await turnContext.SendActivityAsync($"Message did not come from a channel in a team."); } }
public class MyBot : TeamsActivityHandler
# [TypeScript](#tab/typescript)
+* [SDK reference](/javascript/api/botbuilder/teamsinfo?view=botbuilder-ts-latest#botbuilder-teamsinfo-getteamdetails&preserve-view=true)
+* [Sample code reference](https://github.com/OfficeDev/Microsoft-Teams-Samples/blob/main/samples/app-complete-sample/nodejs/server/dialogs/teams/fetchTeamInfoDialog.js#L21)
+ ```typescript export class MyBot extends TeamsActivityHandler { constructor() {
export class MyBot extends TeamsActivityHandler {
// See https://aka.ms/about-bot-activity-message to learn more about the message and other activity types. this.onMessage(async (turnContext, next) => {+
+ // Gets the details for the given team id.
const teamDetails = await TeamsInfo.getTeamDetails(turnContext); if (teamDetails) {+
+ // Sends a message activity to the sender of the incoming activity.
await turnContext.sendActivity(`The group ID is: ${teamDetails.aadGroupId}`); } else { await turnContext.sendActivity('This message did not come from a channel in a team.');
export class MyBot extends TeamsActivityHandler {
# [Python](#tab/python)
+* [SDK reference](/python/api/botbuilder-core/botbuilder.core.teams.teamsinfo?view=botbuilder-py-latest#botbuilder-core-teams-teamsinfo-get-team-details&preserve-view=true)
+ ```python async def _show_details(self, turn_context: TurnContext):+
+ # Gets the details for the given team id.
team_details = await TeamsInfo.get_team_details(turn_context)+
+ # MessageFactory.text(): Specifies the type of text data in a message attachment.
reply = MessageFactory.text(f"The team name is {team_details.name}. The team ID is {team_details.id}. The AADGroupID is {team_details.aad_group_id}.")+
+ # Sends a message activity to the sender of the incoming activity.
await turn_context.send_activity(reply) ```
The following sample code is used to get the list of channels in a team:
# [C#](#tab/dotnet)
+* [SDK reference](/dotnet/api/microsoft.bot.builder.teams.teamsinfo.getteamchannelsasync?view=botbuilder-dotnet-stable#microsoft-bot-builder-teams-teamsinfo-getteamchannelsasync(microsoft-bot-builder-iturncontext-system-string-system-threading-cancellationtoken)&preserve-view=true)
+* [Sample code reference](https://github.com/OfficeDev/Microsoft-Teams-Samples/blob/main/samples/msteams-application-qbot/Source/Microsoft.Teams.Apps.QBot.Web/Bot/QBotTeamInfo.cs#L57)
+ ```csharp public class MyBot : TeamsActivityHandler {
+ // Override this in a derived class to provide logic specific to Message activities.
protected override async Task OnMessageActivityAsync(ITurnContext<IMessageActivity> turnContext, CancellationToken cancellationToken) {
+ // Returns a list of channels in a Team. This only works in team scoped conversations.
IEnumerable<ChannelInfo> channels = await TeamsInfo.GetTeamChannelsAsync(turnContext, turnContext.Activity.TeamsGetTeamInfo().Id, cancellationToken);
+ // Sends a message activity to the sender of the incoming activity.
await turnContext.SendActivityAsync($"The channel count is: {channels.Count()}"); } }
public class MyBot : TeamsActivityHandler
# [TypeScript](#tab/typescript)
+* [SDK reference](/javascript/api/botbuilder/teamsinfo?view=botbuilder-ts-latest#botbuilder-teamsinfo-getteamchannels&preserve-view=true)
+ ```typescript export class MyBot extends TeamsActivityHandler { constructor() {
export class MyBot extends TeamsActivityHandler {
// See https://aka.ms/about-bot-activity-message to learn more about the message and other activity types. this.onMessage(async (turnContext, next) => {+
+ // Supports retrieving channels hosted by a team.
const channels = await TeamsInfo.getTeamChannels(turnContext);
+ // Sends a message activity to the sender of the incoming activity.
await turnContext.sendActivity(`The channel count is: ${channels.length}`); // By calling next() you ensure that the next BotHandler is run.
export class MyBot extends TeamsActivityHandler {
``` # [Python](#tab/python)
+* [SDK reference](/python/api/botbuilder-core/botbuilder.core.teams.teamsinfo?view=botbuilder-py-latest#botbuilder-core-teams-teamsinfo-get-team-channels&preserve-view=true)
```python async def _show_channels( self, turn_context: TurnContext ):
+ # Supports retrieving channels hosted by a team.
channels = await TeamsInfo.get_team_channels(turn_context) reply = MessageFactory.text(f"Total of {len(channels)} channels are currently in team") await turn_context.send_activity(reply)
platform Update And Delete Bot Messages https://github.com/MicrosoftDocs/msteams-docs/commits/main/msteams-platform/bots/how-to/update-and-delete-bot-messages.md
It is not necessary for the new message to match the original in type. For examp
# [C#](#tab/dotnet)
+* [SDK reference](/dotnet/api/microsoft.bot.builder.botadapter.updateactivityasync?view=botbuilder-dotnet-stable#microsoft-bot-builder-botadapter-updateactivityasync(microsoft-bot-builder-iturncontext-microsoft-bot-schema-activity-system-threading-cancellationtoken)&preserve-view=true)
+* [Sample code reference](https://github.com/OfficeDev/Microsoft-Teams-Samples/blob/main/samples/bot-conversation/csharp/Bots/TeamsConversationBot.cs#L257)
+ To update an existing message, pass a new `Activity` object with the existing activity ID to the `UpdateActivityAsync` method of the `TurnContext` class. For more information, see [TurnContextClass](/dotnet/api/microsoft.bot.builder.turncontext?view=botbuilder-dotnet-stable&preserve-view=true). ```csharp
+// MessageFactory.Text(): Specifies the type of text data in a message attachment.
var newActivity = MessageFactory.Text("The new text for the activity"); newActivity.Id = activityId;+
+// UpdateActivityAsync(): A method that can participate in update activity events for the current turn.
await turnContext.UpdateActivityAsync(newActivity, cancellationToken); ```
await turnContext.UpdateActivityAsync(newActivity, cancellationToken);
To update an existing message, pass a new `Activity` object with the existing activity ID to the `updateActivity` method of the `TurnContext` object. For more information, see [updateActivity](/javascript/api/botbuilder-core/turncontext?view=botbuilder-ts-latest#updateactivity-partial-activity--&preserve-view=true). ```typescript
+// MessageFactory.Text(): Specifies the type of text data in a message attachment.
const newActivity = MessageFactory.text('The new text for the activity'); newActivity.id = activityId;+
+// A method that can participate in update activity events for the current turn.
await turnContext.updateActivity(newActivity); ``` # [Python](#tab/python)
+* [SDK reference](/python/api/botbuilder-core/botbuilder.core.turncontext?view=botbuilder-py-latest#botbuilder-core-turncontext-update-activity&preserve-view=true)
To update an existing message, pass a new `Activity` object with the existing activity ID to the `update_activity` method of the `TurnContext` class. See [TurnContextClass](/python/api/botbuilder-core/botbuilder.core.turncontext?view=botbuilder-py-latest&preserve-view=true). ```python
+# MessageFactory.Text(): Specifies the type of text data in a message attachment.
new_activity = MessageFactory.text("The new text for the activity") new_activity.id = activity_id+
+# A method that can participate in update activity events for the current turn.
update_result = await context.update_activity(new_activity) ```
To update the existing card on button selection, you can use `ReplyToId` of inco
To update existing card on a button selection, pass a new `Activity` object with updated card and `ReplyToId` as activity ID to the `UpdateActivityAsync` method of the `TurnContext` class. See [TurnContextClass](/dotnet/api/microsoft.bot.builder.turncontext?view=botbuilder-dotnet-stable&preserve-view=true). ```csharp
+// Returns a message activity that contains an attachment.
var activity = MessageFactory.Attachment(card.ToAttachment()); activity.Id = turnContext.Activity.ReplyToId;+
+// A method that can participate in update activity events for the current turn.
await turnContext.UpdateActivityAsync(activity, cancellationToken); ``` # [TypeScript](#tab/typescript)
+* [SDK reference](/javascript/api/botbuilder-core/turncontext?view=botbuilder-ts-latest#botbuilder-core-turncontext-updateactivity&preserve-view=true)
+* [Sample code reference](https://github.com/OfficeDev/Microsoft-Teams-Samples/blob/main/samples/bot-conversation/nodejs/bots/teamsConversationBot.js#L133)
To update existing card on a button selection, pass a new `Activity` object with updated card and `replyToId` as activity ID to the `updateActivity` method of the `TurnContext` object. See [updateActivity](/javascript/api/botbuilder-core/turncontext?view=botbuilder-ts-latest#updateactivity-partial-activity--&preserve-view=true). ```typescript
+// MessageFactory.attachment(): Returns a message activity that contains an attachment.
const message = MessageFactory.attachment(card); message.id = context.activity.replyToId;+
+// updateActivity(): A method that can participate in update activity events for the current turn.
await context.updateActivity(message); ``` # [Python](#tab/python)
+* [SDK reference](/python/api/botbuilder-core/botbuilder.core.turncontext?view=botbuilder-py-latest#botbuilder-core-turncontext-update-activity&preserve-view=true)
To update existing card on a button click, pass a new `Activity` object with updated card and `reply_to_id` as activity ID to the `update_activity` method of the `TurnContext` class. See [TurnContextClass](/python/api/botbuilder-core/botbuilder.core.turncontext?view=botbuilder-py-latest&preserve-view=true). ```python
+# MessageFactory.attachment(): Returns a message activity that contains an attachment.
updated_activity = MessageFactory.attachment(CardFactory.hero_card(card)) updated_activity.id = turn_context.activity.reply_to_id+
+# update_activity(): A method that can participate in update activity events for the current turn.
await turn_context.update_activity(updated_activity) ```
In the Bot Framework, every message has its unique activity identifier. Messages
# [C#](#tab/dotnet)
+* [SDK reference](/dotnet/api/microsoft.bot.builder.botadapter.deleteactivityasync?view=botbuilder-dotnet-stable#microsoft-bot-builder-botadapter-deleteactivityasync(microsoft-bot-builder-iturncontext-microsoft-bot-schema-conversationreference-system-threading-cancellationtoken)&preserve-view=true)
+* [Sample code reference](https://github.com/OfficeDev/Microsoft-Teams-Samples/blob/main/samples/bot-conversation/csharp/Bots/TeamsConversationBot.cs#L156)
+ To delete a message, pass that activity's ID to the `DeleteActivityAsync` method of the `TurnContext` class. For more information, see [TurnContext.DeleteActivityAsync Method](/dotnet/api/microsoft.bot.builder.turncontext.deleteactivityasync?view=botbuilder-dotnet-stable&preserve-view=true). ```csharp foreach (var activityId in _list) {
+ // When overridden in a derived class, deletes an existing activity in the conversation.
await turnContext.DeleteActivityAsync(activityId, cancellationToken); } ``` # [TypeScript](#tab/typescript)
+* [SDK reference](/javascript/api/botbuilder-core/turncontext?view=botbuilder-ts-latest#botbuilder-core-turncontext-deleteactivity&preserve-view=true)
+* [Sample code reference](https://github.com/OfficeDev/Microsoft-Teams-Samples/blob/main/samples/bot-conversation/nodejs/bots/teamsConversationBot.js#L218)
To delete a message, pass that activity's ID to the `deleteActivity` method of the `TurnContext` object. For more information, see [deleteActivity](/javascript/api/botbuilder-core/turncontext?view=botbuilder-ts-latest#deleteactivity-stringpartial-conversationreference--&preserve-view=true). ```typescript for (let i = 0; i < activityIds.length; i++) {
+ // deleteActivity(): deletes an existing activity in the conversation.
await turnContext.deleteActivity(activityIds[i]); } ``` # [Python](#tab/python)
+* [SDK reference](/python/api/botbuilder-core/botbuilder.core.turncontext?view=botbuilder-py-latest#botbuilder-core-turncontext-delete-activity&preserve-view=true)
To delete that message, pass that activity's ID to the `delete_activity` method of the `TurnContext` object. For more information, see [activity-update-and-delete](https://github.com/microsoft/botbuilder-python/blob/c04ecacb22c1f4b43a671fe2f1e4782218391975/tests/teams/scenarios/activity-update-and-delete/bots/activity_update_and_delete_bot.py). ```python for each activity_id in _list:
+ # delete_activity(): deletes an existing activity in the conversation.
await TurnContext.delete_activity(activity_id) ```
platform Graph Proactive Bots And Messages https://github.com/MicrosoftDocs/msteams-docs/commits/main/msteams-platform/graph-api/proactive-bots-and-messages/graph-proactive-bots-and-messages.md
The following code provides an example of sending proactive messages:
# [C#](#tab/dotnet)
+* [SDK reference](/dotnet/api/microsoft.bot.builder.cloudadapterbase.continueconversationasync?view=botbuilder-dotnet-stable#microsoft-bot-builder-cloudadapterbase-continueconversationasync(system-string-microsoft-bot-schema-activity-microsoft-bot-builder-botcallbackhandler-system-threading-cancellationtoken)&preserve-view=true)
+* [Sample code reference](https://github.com/OfficeDev/Microsoft-Teams-Samples/blob/main/samples/graph-meeting-notification/csharp/MeetingNotification/Controllers/NotificationController.cs#L112)
+ ```csharp public async Task<int> SendNotificationToAllUsersAsync(ITurnContext<IMessageActivity> turnContext, CancellationToken cancellationToken) { int msgSentCount = 0;
- // Send notification to all the members
+ // Send notification to all the members.
foreach (var conversationReference in _conversationReferences.Values) { await turnContext.Adapter.ContinueConversationAsync(_configuration["MicrosoftAppId"], conversationReference, BotCallback, cancellationToken);
public async Task<int> SendNotificationToAllUsersAsync(ITurnContext<IMessageActi
private async Task BotCallback(ITurnContext turnContext, CancellationToken cancellationToken) {
+ // Sends an activity to the sender of the incoming activity.
await turnContext.SendActivityAsync("Proactive hello."); } ``` # [Node.js](#tab/nodejs)
+* [Sample code reference](https://github.com/OfficeDev/Microsoft-Teams-Samples/blob/main/samples/bot-initiate-thread-in-channel/nodejs/bots/teamsStartNewThreadInChannel.js#L20)
+ ```javascript server.get('/api/notify', async (req, res) => { for (const conversationReference of Object.values(conversationReferences)) {+
+ // Sends a proactive message to a conversation.
await adapter.continueConversationAsync(process.env.MicrosoftAppId, conversationReference, async context => { await context.sendActivity('proactive hello'); }); }- res.setHeader('Content-Type', 'text/html'); res.writeHead(200); res.write('<html><body><h1>Proactive messages have been sent.</h1></body></html>');
platform Respond To Search https://github.com/MicrosoftDocs/msteams-docs/commits/main/msteams-platform/messaging-extensions/how-to/search-commands/respond-to-search.md
The request parameters are found in the `value` object in the request, which inc
```csharp protected override async Task<MessagingExtensionResponse> OnTeamsMessagingExtensionQueryAsync(ITurnContext<IInvokeActivity> turnContext, MessagingExtensionQuery query, CancellationToken cancellationToken) {
- //code to handle the query
+ // Code to handle the query.
} ``` # [TypeScript/Node.js](#tab/typescript)
+* [Sample code reference](https://github.com/OfficeDev/Microsoft-Teams-Samples/blob/main/samples/msgext-search/nodejs/bots/teamsMessagingExtensionsSearchBot.js#L16)
+ ```typescript class TeamsMessagingExtensionsSearch extends TeamsActivityHandler { async handleTeamsMessagingExtensionQuery(context, query) {
- //code to handle the query
+ // Code to handle the query.
} } ```
protected override async Task<MessagingExtensionResponse> OnTeamsMessagingExtens
{ var text = query?.Parameters?[0]?.Value as string ?? string.Empty;
- //searches NuGet for a package
+ // Searches NuGet for a package.
var obj = JObject.Parse(await (new HttpClient()).GetStringAsync($"https://azuresearch-usnc.nuget.org/query?q=id:{text}&prerelease=true")); var packages = obj["data"].Select(item => (item["id"].ToString(), item["version"].ToString(), item["description"].ToString()));
protected override async Task<MessagingExtensionResponse> OnTeamsMessagingExtens
# [TypeScript/Node.js](#tab/typescript)
+* [Sample code reference](https://github.com/OfficeDev/Microsoft-Teams-Samples/blob/main/samples/msgext-search-quickstart/js/botActivityHandler.js#L35)
+ ```typescript class TeamsMessagingExtensionsSearchBot extends TeamsActivityHandler { async handleTeamsMessagingExtensionQuery(context, query) {
class TeamsMessagingExtensionsSearchBot extends TeamsActivityHandler {
```csharp protected override Task<MessagingExtensionResponse> OnTeamsMessagingExtensionSelectItemAsync(ITurnContext<IInvokeActivity> turnContext, JObject query, CancellationToken cancellationToken) {
- // The Preview card's Tap should have a Value property assigned, this will be returned to the bot in this event.
+ // The Preview card's Tap should have a Value property assigned, this will be returned to the bot in this event.
var (packageId, version, description, projectUrl, iconUrl) = query.ToObject<(string, string, string, string, string)>(); var card = new ThumbnailCard
protected override Task<MessagingExtensionResponse> OnTeamsMessagingExtensionSel
# [TypeScript/Node.js](#tab/typescript)
+* [Sample code reference](https://github.com/OfficeDev/Microsoft-Teams-Samples/blob/main/samples/msgext-search/nodejs/bots/teamsMessagingExtensionsSearchBot.js#L115)
+ ```typescript async handleTeamsMessagingExtensionSelectItem(context, obj) { return {
async handleTeamsMessagingExtensionSelectItem(context, obj) {
* * * > [!NOTE]
-> `OnTeamsMessagingExtensionSelectItemAsync` is not triggered in mobile teams application.
+> `OnTeamsMessagingExtensionSelectItemAsync` is not triggered in mobile Teams application.
## Default query
platform What Are Messaging Extensions https://github.com/MicrosoftDocs/msteams-docs/commits/main/msteams-platform/messaging-extensions/what-are-messaging-extensions.md
The following code provides an example of action based for message extensions:
# [C#](#tab/dotnet)
-```csharp
+* [SDK reference](/microsoftteams/platform/messaging-extensions/how-to/action-commands/create-task-module?tabs=dotnet#respond-to-the-fetchtask-with-an-adaptive-card)
+* [Sample code reference](https://github.com/OfficeDev/Microsoft-Teams-Samples/blob/main/samples/msgext-action-preview/csharp/Bots/TeamsMessagingExtensionsActionPreviewBot.cs#L35-L56)
- protected override Task<MessagingExtensionActionResponse> OnTeamsMessagingExtensionFetchTaskAsync(ITurnContext<IInvokeActivity> turnContext, MessagingExtensionAction action, CancellationToken cancellationToken)
+```csharp
+ protected override Task<MessagingExtensionActionResponse> OnTeamsMessagingExtensionFetchTaskAsync(ITurnContext<IInvokeActivity> turnContext, MessagingExtensionAction action, CancellationToken cancellationToken)
{
- // Handle different actions using switch
+ // Handle different actions using switch.
switch (action.CommandId) { case "HTML":
The following code provides an example of action based for message extensions:
# [Node.js](#tab/nodejs)
-```javascript
+* [SDK reference](/microsoftteams/platform/messaging-extensions/how-to/action-commands/create-task-module?tabs=javascript#respond-to-the-fetchtask-with-an-adaptive-card)
+* [Sample code reference](https://github.com/OfficeDev/Microsoft-Teams-Samples/blob/main/samples/msgext-action/nodejs/bots/teamsMessagingExtensionsActionBot.js#L24-L61)
+```javascript
+// Invoked when a Messaging Extension Fetch activity is received from the connector.
async handleTeamsMessagingExtensionFetchTask(context, action) { switch (action.commandId) { case 'Static HTML':
The following code provides an example of action based for message extensions:
} }; }- ```
The following code provides an example of search based for message extensions:
# [C#](#tab/dotnet)
-```csharp
+* [SDK reference](/dotnet/api/microsoft.identity.client.confidentialclientapplication.acquiretokenonbehalfof?source=recommendations&view=azure-dotnet&preserve-view=true)
+* [Sample code reference](https://github.com/OfficeDev/Microsoft-Teams-Samples/blob/main/samples/app-hello-world/csharp/Microsoft.Teams.Samples.HelloWorld.Web/Bots/MessageExtension.cs#L26-L59)
+```csharp
protected override async Task<MessagingExtensionResponse> OnTeamsMessagingExtensionQueryAsync(ITurnContext<IInvokeActivity> turnContext, MessagingExtensionQuery query, CancellationToken cancellationToken) { var text = query?.Parameters?[0]?.Value as string ?? string.Empty;
protected override async Task<MessagingExtensionResponse> OnTeamsMessagingExtens
# [Node.js](#tab/nodejs)
-```javascript
+* [SDK reference](/dotnet/api/microsoft.identity.client.confidentialclientapplication.acquiretokenonbehalfof?source=recommendations&view=azure-dotnet&preserve-view=true)
+* [Sample code reference](https://github.com/OfficeDev/Microsoft-Teams-Samples/blob/main/samples/msgext-search-quickstart/js/botActivityHandler.js#L30-L53)
+
+```javascript
async handleTeamsMessagingExtensionQuery(context, query) { const searchQuery = query.parameters[0].value; const attachments = [];
platform Overview Solution https://github.com/MicrosoftDocs/msteams-docs/commits/main/msteams-platform/overview-solution.md
Last updated 11/02/2021
# The Teams solution - The Microsoft Teams Platform is a powerful, flexible platform for creating apps for Teams. It provides a vast suite of development environments and tools to support app development. ## The user story + You've had a view of Teams offerings. You can now map them to user needs. LetΓÇÖs revisit the scenario. The developer from Tours and Travel agency wants to build an app for their users, the travelers. The app must:
platform Create Extensions https://github.com/MicrosoftDocs/msteams-docs/commits/main/msteams-platform/resources/messaging-extension-v3/create-extensions.md
When responding to the `edit` request, you should respond with a `task` response
# [TypeScript/Node.js](#tab/typescript)
+* [Sample code reference](https://github.com/OfficeDev/Microsoft-Teams-Samples/blob/main/samples/msgext-search/nodejs/bots/teamsMessagingExtensionsSearchBot.js#L115)
+ ```typescript teamChatConnector.onComposeExtensionSubmitAction(( event: builder.IEvent,
teamChatConnector.onComposeExtensionSubmitAction((
teamChatConnector.send([msg.toMessage()], (error) => { if(error){
- //TODO: Handle error and callback
+ // TODO: Handle error and callback.
} else { callback(null, null, 200);
teamChatConnector.onComposeExtensionSubmitAction((
} else if (invokeValue.botMessagePreviewAction === 'edit') {
- // Create the card and populate with user-inputted information
+ // Create the card and populate with user-inputted information.
let card = { ... } let taskResponse = {
teamChatConnector.onComposeExtensionSubmitAction((
else { let attachment = {
- //create adaptive card
+ // Create adaptive card.
}; let activity = new builder.Message().addAttachment(attachment).toMessage(); let response = teamBuilder.ComposeExtensionResponse.messagePreview()
public class MessagesController : ApiController
if (activity.Type == ActivityTypes.Invoke) {
- // Initial task module presented to the user
+ // Initial task module presented to the user.
if (activity.Name == "composeExtension/fetchTask") { string task = GetTaskModule();
public class MessagesController : ApiController
dynamic activityValue = JObject.FromObject(activity.Value); string botMessagePreviewAction = activityValue["botMessagePreviewAction"];
- //This is the initial card response sent after the task module is submitted
+ // This is the initial card response sent after the task module is submitted.
if (botMessagePreviewAction is null) { string text = activityValue.data.cardMessage;
public class MessagesController : ApiController
} else {
- //This is the "send the card to the channel" event
+ // This is the "send the card to the channel" event.
if (botMessagePreviewAction.Equals("send")) { string cardJson = JsonConvert.SerializeObject(activityValue.botActivityPreview[0].attachments[0].content);
public class MessagesController : ApiController
var result = await connectorClient.Conversations.SendToConversationAsync(response); }
- //This is fired if the user edits the card before sending it
+ // This is fired if the user edits the card before sending it.
else if (botMessagePreviewAction.Equals("edit")) { string task = GetTaskModule();
public class MessagesController : ApiController
string cardJson = card.ToJson();
- //Create the task module response
+ // Create the task module response.
string task = $@"{{ 'task': {{ 'type': 'continue',
platform Tab Sso Graph Api https://github.com/MicrosoftDocs/msteams-docs/commits/main/msteams-platform/tabs/how-to/authentication/tab-sso-graph-api.md
The following code provides an example of OBO flow to fetch access token from th
### [C#](#tab/dotnet)
-```csharp
+- SDK reference
+- [Sample code reference](https://github.com/OfficeDev/Microsoft-Teams-Samples/blob/main/samples/graph-app-installation-lifecycle/csharp/AppInstallation/Controllers/BaseController.cs&preserve-view=true)
+```csharp
IConfidentialClientApplication app = ConfidentialClientApplicationBuilder.Create(<"Client id">) .WithClientSecret(<"Client secret">) .WithAuthority($"https://login.microsoftonline.com/<"Tenant id">") .Build();
-
try { var idToken = <"Client side token">; UserAssertion assert = new UserAssertion(idToken); List<string> scopes = new List<string>(); scopes.Add("https://graph.microsoft.com/User.Read");
+ // Acquires an access token for this application (usually a Web API) from the authority configured in the application.
var responseToken = await app.AcquireTokenOnBehalfOf(scopes, assert).ExecuteAsync(); return responseToken.AccessToken.ToString(); }
IConfidentialClientApplication app = ConfidentialClientApplicationBuilder.Create
### [Node.js](#tab/nodejs)
-```Node.js
+- [SDK reference](/javascript/api/@azure/msal-node/confidentialclientapplication?view=azure-node-latest#@azure-msal-node-confidentialclientapplication-acquiretokenonbehalfof&preserve-view=true)
+- [sample code reference](https://github.com/OfficeDev/Microsoft-Teams-Samples/blob/main/samples/tab-sso/nodejs/src/server/tabs.js#L51-L94)
+```Node.js
// Exchange client Id side token with server token app.post('/getProfileOnBehalfOf', function(req, res) { var tid = < "Tenant id" >
platform Teamsfx SDK https://github.com/MicrosoftDocs/msteams-docs/commits/main/msteams-platform/toolkit/TeamsFx-SDK.md
Last updated 11/29/2021
# TeamsFx SDK
-TeamsFx helps to reduce your tasks by using Microsoft Teams Single-Sign-On (Teams SSO) and accessing cloud resources down to single line statements with zero configuration. You can use TeamsFx SDK in browser and Node.js environment. TeamsFx core functionalities can be accessed in client and server environment. You can write user authentication code in a simplified way for:
+TeamsFx helps to reduce your tasks by using Microsoft Teams single sign-on (SSO) and accessing cloud resources down to single line statements with zero configuration. You can use TeamsFx SDK in the browser and Node.js environments. TeamsFx core functionalities can be accessed in client and server environments. You can write user authentication code for:
* Teams tab * Teams bot
You need to install the following tools and set up your development environment:
| &nbsp; | [Visual Studio Code](https://code.visualstudio.com/download) | JavaScript, TypeScript, or SharePoint Framework (SPFx) build environments. Use version 1.55 or later. | | &nbsp; | [Teams Toolkit](https://marketplace.visualstudio.com/items?itemName=TeamsDevApp.ms-teams-vscode-extension)| A Microsoft Visual Studio Code extension that creates a project scaffolding for your app. Use 4.0.0 version. | | &nbsp; | [Node.js](https://nodejs.org/en/download/) | Back-end JavaScript runtime environment. Use the latest v16 LTS release.|
- | &nbsp; | [Microsoft Teams](https://www.microsoft.com/microsoft-teams/download-app) | Microsoft Teams to collaborate with everyone you work with through apps for chat, meetings, call - all in one place.|
+ | &nbsp; | [Microsoft Teams](https://www.microsoft.com/microsoft-teams/download-app) | Microsoft Teams to collaborate with everyone you work with through apps for chat, meetings, call and all in one place.|
| &nbsp; | [Microsoft&nbsp;Edge](https://www.microsoft.com/edge) (recommended) or [Google Chrome](https://www.google.com/chrome/) | A browser with developer tools. | > [!NOTE]
-> If your project has installed `botbuilder` related [packages](https://github.com/Microsoft/botbuilder-js#packages) as dependencies, ensure they are of the same version.
+> If your project has installed `botbuilder`related [packages](https://github.com/Microsoft/botbuilder-js#packages) as dependencies, ensure they are of the same version.
You must have working knowledge of:
You must have working knowledge of:
TeamsFx SDK is pre-configured in the scaffolded project using TeamsFx Toolkit or CLI. For more information, see [Teams app project](https://github.com/OfficeDev/TeamsFx/blob/main/packages/vscode-extension/README.md).
+ > [!Tip]
+ > The code snippets are updated for the latest TeamsFx SDK version 2.
+ ### Install the `@microsoft/teamsfx` package Install the TeamsFx SDK for TypeScript or JavaScript with `npm`:
npm install @microsoft/teamsfx
### TeamsFx class
-TeamsFx class instance access all TeamsFx settings from environment variables by default. You can also set customized configuration values to override the default values. Check [override configuration](#override-configuration) for details.
-When creating a TeamsFx instance, you also need to specify the identity type.
-There are two identity types:
+TeamsFx class instance access all TeamsFx settings from the environment variables by default. You can set customized configuration values to override the default values. For more information, see [override configuration](#override-configuration-for-teamsfx-class) for details.
+When creating a TeamsFx instance, you need to specify the identity type.
+
+The following list provides the two different type of identities:
* **User Identity**: Represents the current user of Teams. * **Application Identity**: Represents the application itself. > [!NOTE]
- > For these two identity types, the TeamsFx constructors and methods aren't the same.
+ > The TeamsFx constructors and methods aren't the same for these two identity types.
You can learn more about user identity and application identity in the following section:
You can learn more about user identity and application identity in the following
| Command | Description | |-|-| | `new TeamsFx(IdentityType.App)`| Application is authenticated as an application. The permission usually needs administrator's approval.|
-| `TeamsFx:getCredential()`| Its provides credential instances automatically corresponding to identity type. |
+| `TeamsFx:getCredential()`| It provides credential instances automatically corresponding to the identity type. |
> [!NOTE] > You need admin consent for resources. </details>
+> [!NOTE]
+> TeamsFx class has been deprecated, use `TeamsUserCredential`, `OnBehalfOfUserCredential`, and `AppCredential` instead.
+ ### Credential
-To initialize TeamsFx, you must choose the required identity type. Post specifying the identity type SDK uses different type of credential class. These represent the identity and get access token by corresponding auth flow. Credential classes implement `TokenCredential` interface that is broadly used in Azure library APIs designed to provide access tokens for specific scopes. Other APIs rely on credential call `TeamsFx:getCredential()` to get an instance of `TokenCredential`. For more information on credential and auth flow related classes, see [credential folder](https://github.com/OfficeDev/TeamsFx/tree/main/packages/sdk/src/credential).
+Credential classes implement the `TokenCredential` interface that is broadly used in Azure library APIs designed to provide access tokens for specific scopes. For more information on credential and auth flow related classes, see [credential folder](https://github.com/OfficeDev/TeamsFx/tree/main/packages/sdk/src/credential).
There are three credential classes to simplify authentication. Here's the corresponding scenarios for each credential class target. <details>
-<summary><b> User Identity in browser environment </b></summary>
+<summary><b> User identity in browser environment </b></summary>
+
+`TeamsUserCredential` represents Teams current user's identity. For the first time user's credentials are authenticated, then Teams SSO does the On-Behalf-Of flow for token exchange. SDK uses this credential when you choose user identity in the browser environment.
+
+The following code is an an example to create `TeamsUserCredential`:
+
+```typescript
+const authConfig: TeamsUserCredentialAuthConfig = {
+ clientId: process.env.REACT_APP_CLIENT_ID,
+ initiateLoginEndpoint: process.env.REACT_APP_START_LOGIN_PAGE_URL,
+};
-`TeamsUserCredential` represents Teams current user's identity. For the first time user's credentials are authenticated, then Teams SSO does the On-Behalf-Of flow for token exchange. SDK uses this credential when you choose user identity in browser environment.
+const credential = new TeamsUserCredential(authConfig);
+```
+
+Required configurations are `initiateLoginEndpoint` and `clientId` which can be found inside type `TeamsUserCredentialAuthConfig`.
-The required configurations are: `initiateLoginEndpoint` and `clientId`.
</details> <details>
-<summary><b> User Identity in Node.js environment </b></summary>
+<summary><b> User identity in Node.js environment </b></summary>
+
+`OnBehalfOfUserCredential` uses On-Behalf-Of flow and require Teams SSO token, in Azure Function or bot scenarios. TeamsFx SDK uses the following credential when you choose user identity in Node.js environment.
+
+The following code is an example to create `OnBehalfOfUserCredential`:
-`OnBehalfOfUserCredential` uses On-Behalf-Of flow and require Teams SSO token, in Azure function or bot scenarios. TeamsFx SDK uses the following credential when you choose user identity in Node.js environment.
+```typescript
+const oboAuthConfig: OnBehalfOfCredentialAuthConfig = {
+ authorityHost: process.env.M365_AUTHORITY_HOST,
+ clientId: process.env.M365_CLIENT_ID,
+ tenantId: process.env.M365_TENANT_ID,
+ clientSecret: process.env.M365_CLIENT_SECRET,
+};
+
+const oboCredential = new OnBehalfOfUserCredential(ssoToken, oboAuthConfig);
+```
+
+Required configurations are `authorityHost`, `tenantId`, `clientId`, `clientSecret`, or `certificateContent` which can be found inside type `OnBehalfOfCredentialAuthConfig`.
-Required configuration: `authorityHost`, `tenantId`, `clientId`, `clientSecret` or `certificateContent`.
</details> <details>
-<summary><b> App Identity in Node.js environment </b></summary>
+<summary><b> App identity in Node.js environment </b></summary>
+
+`AppCredential` represents the app identity. You can use app identity when user isn't involved, for example, in a time-triggered automation job. TeamsFx SDK uses the following credential when you choose app identity in Node.js environment.
-`AppCredential` represents the app identity. You can use app identity when user isn't involved, for example in a time-triggered automation job. TeamsFx SDK uses the following credential when you choose app identity in Node.js environment.
+The following code is an example to create `AppCredential`:
-Required configuration: `tenantId`, `clientId`, `clientSecret` or `certificateContent`.
+```typescript
+const appAuthConfig: AppCredentialAuthConfig = {
+ authorityHost: process.env.M365_AUTHORITY_HOST,
+ clientId: process.env.M365_CLIENT_ID,
+ tenantId: process.env.M365_TENANT_ID,
+ clientSecret: process.env.M365_CLIENT_SECRET,
+};
+const appCredential = new AppCredential(appAuthConfig);
+```
+
+Required configurations are `authorityHost`, `tenantId`, `clientId`, `clientSecret`, or `certificateContent` which can be found inside type `AppCredentialAuthConfig`
</details> ### Bot SSO Bot related classes are stored under [bot folder](https://github.com/OfficeDev/TeamsFx/tree/main/packages/sdk/src/bot).
-`TeamsBotSsoPrompt` integrates with bot framework. It simplifies the authentication process when you develop bot application and want to use the bot SSO.
+`TeamsBotSsoPrompt` integrates with the bot framework. It simplifies the authentication process when you develop bot application and want to use the bot SSO.
+
+The following code is an example to create `TeamsBotSsoPrompt`:
-Required configuration: `initiateLoginEndpoint`, `tenantId`, `clientId`, and `applicationIdUri`.
+```typescript
+const TeamsBotSsoPromptId = "TEAMS_BOT_SSO_PROMPT";
+
+const settings: TeamsBotSsoPromptSettings = {
+ scopes: ["User.Read"],
+ timeout: 900000,
+ endOnInvalidMessage: true,
+};
+
+const authConfig: OnBehalfOfCredentialAuthConfig = {
+ authorityHost: process.env.M365_AUTHORITY_HOST,
+ clientId: process.env.M365_CLIENT_ID,
+ tenantId: process.env.M365_TENANT_ID,
+ clientSecret: process.env.M365_CLIENT_SECRET,
+};
+const loginUrl = process.env.INITIATE_LOGIN_ENDPOINT;
+const ssoPrompt = new TeamsBotSsoPrompt(authConfig, loginUrl, TeamsBotSsoPromptId, settings);
+```
### Supported functions TeamsFx SDK provides several functions to ease the configuration for third-party libraries. They're located under [core folder](https://github.com/OfficeDev/TeamsFx/tree/main/packages/sdk/src/core).
-* Microsoft Graph Service:`createMicrosoftGraphClient` and `MsGraphAuthProvider` help to create authenticated Graph instance.
-* SQL:`getTediousConnectionConfig` returns a tedious connection config.
+* Microsoft Graph Service:`createMicrosoftGraphClient`, `createMicrosoftGraphClientWithCredential`, and `MsGraphAuthProvider` helps to create authenticated Graph instance.
+
+ > [!NOTE]
+ > `createMicrosoftGraphClient` function has been deprecated. We recommend you to use `createMicrosoftGraphClientWithCredential` instead for better coding experience.
+
+* SQL: The `getTediousConnectionConfig` returns a tedious connection config.
Required configuration:
- * If you want to use user identity, then `sqlServerEndpoint`, `sqlUsername` and `sqlPassword` are required.
+ * If you want to use user identity, then `sqlServerEndpoint`, `sqlUsername`, and `sqlPassword` are required.
* If you want to use MSI identity, then `sqlServerEndpoint`and `sqlIdentityId` are required.
-### Override configuration
+ > [!NOTE]
+ > The `getTediousConnectionConfig` function has been deprecated. We recommend you compose your own Tedious configuration for better flexibility.
+
+### Override configuration for TeamsFx class
+
+> [!NOTE]
+> TeamsFx class has been deprecated. Use `TeamsUserCredential`, `OnBehalfOfUserCredential`, and `AppCredential` instead.
You can pass custom config when creating a new `TeamsFx` instance to override default configuration or set required fields when `environment variables` are missing.
You can pass custom config when creating a new `TeamsFx` instance to override de
For tab project </b> </summary>
-If you've created tab project using Microsoft Visual Studio Code Toolkit, the following config values will be used from pre-configured environment variables:
+If you've created tab project using Microsoft Visual Studio Code Toolkit, the following config values is used from pre-configured environment variables:
* authorityHost (REACT_APP_AUTHORITY_HOST) * tenantId (REACT_APP_TENANT_ID)
If you've created tab project using Microsoft Visual Studio Code Toolkit, the fo
<details> <summary><b>
-For Azure function or bot project
+For Azure Function or bot project
</b></summary>
-If you've created Azure function or bot project using Visual Studio Code Toolkit, the following config values will be used from pre-configured environment variables:
+If you've created Azure Function or bot project using Visual Studio Code Toolkit, the following config values is used from pre-configured environment variables:
* initiateLoginEndpoint (INITIATE_LOGIN_ENDPOINT) * authorityHost (M365_AUTHORITY_HOST)
try {
} ```
-If credential instance is used in other library such as Microsoft Graph, it's possible that error is caught and transformed.
+> [!NOTE]
+> TeamsFx class has been deprecated, and `ErrorWithCode` code is not recommended. You can use `TeamsUserCredential` instead as follow:
+
+```typescript
+try {
+ const authConfig: TeamsUserCredentialAuthConfig = {
+ clientId: process.env.REACT_APP_CLIENT_ID,
+ initiateLoginEndpoint: process.env.REACT_APP_START_LOGIN_PAGE_URL,
+ };
+
+ const credential = new TeamsUserCredential(authConfig);
+ await credential.login("User.Read");
+} catch (err: unknown) {
+ if (err instanceof ErrorWithCode && err.code !== ErrorCode.ConsentFailed) {
+ throw err;
+ } else {
+ // Silently fail because user cancels the consent dialog
+ return;
+ }
+}
+```
+
+If a credential instance is used in other library, such as Microsoft Graph, it's possible that an error is caught and transformed.
## Microsoft Graph Scenarios
-This section provides several code snippets for common scenarios that are related to Microsoft Graph. In such scenarios, user can call APIs using different permissions in different ends(frontend/backend).
+This section provides several code snippets for common scenarios that are related to the Microsoft Graph. In such scenarios, user can call APIs using different permissions in different ends, such as frontend or backend.
-* User delegate permission in frontend (Use TeamsUserCredential)
+* User delegate permission in frontend (Use `TeamsUserCredential`)
<details> <summary><b>Use graph API in tab app</b></summary>
- This code snippet shows you how to use `TeamsFx` and `createMicrosoftGraphClient` to get user profiles from Microsoft Graph. It also shows you how to catch and resolve a `GraphError`.
+ This code snippet shows you how to use `TeamsUserCredential` and `createMicrosoftGraphClientWithCredential` to get user profiles from Microsoft Graph in tab app. It also shows you how to catch and resolve a `GraphError`.
1. Import the classes needed.
- ```typescript
- import {
- createMicrosoftGraphClient,
- TeamsFx,
- } from "@microsoft/teamsfx";
- ```
-
- 2. Use `TeamsFx.login()` to get user consent.
-
- ```typescript
- // Put these code in a call-to-action callback function to avoid browser blocking automatically showing up pop-ups.
- await teamsfx.login(["User.Read"]); // Login with scope
- ```
-
- 3. You can initialize a TeamsFx instance and graph client and get information from MS Graph by this client.
-
- ```typescript
- try {
- const teamsfx = new TeamsFx();
- const graphClient = createMicrosoftGraphClient(teamsfx, ["User.Read"]); // Initializes MS Graph SDK using our MsGraphAuthProvider
- const profile = await graphClient.api("/me").get();
- } catch (err: unknown) {
- // ErrorWithCode is handled by Graph client
- if (err instanceof GraphError && err.code?.includes(ErrorCode.UiRequiredError)) {
- // Need to show login button to ask for user consent.
- }
- }
- ```
+ ```typescript
+ import {
+ createMicrosoftGraphClientWithCredential,
+ TeamsUserCredential,
+ } from "@microsoft/teamsfx";
+ ```
+
+ 2. Create `TeamsUserCredential` instance.
+
+ ```typescript
+ const authConfig: TeamsUserCredentialAuthConfig = {
+ clientId: process.env.REACT_APP_CLIENT_ID,
+ initiateLoginEndpoint: process.env.REACT_APP_START_LOGIN_PAGE_URL,
+ };
+
+ const teamsUserCredential = new TeamsUserCredential(authConfig);
+ ```
+
+ 3. Use `teamsUserCredential.login()` to get user consent.
+
+ ```typescript
+ // Put these code in a call-to-action callback function to avoid browser blocking automatically showing up pop-ups.
+ await teamsUserCredential.login(["User.Read"]); // Login with scope
+ ```
+
+ 4. You can initialize a TeamsFx instance and graph client and get information from Microsoft Graph by this client.
+
+ ```typescript
+ try {
+ const graphClient = createMicrosoftGraphClientWithCredential(teamsUserCredential, ["User. Read"]); // Initializes MS Graph SDK using our MsGraphAuthProvider
+ const profile = await graphClient.api("/me").get();
+ } catch (err: unknown) {
+ // ErrorWithCode is handled by Graph client
+ if (err instanceof GraphError && err.code?.includes(ErrorCode.UiRequiredError)) {
+ // Need to show login button to ask for user consent.
+ }
+ }
+ ```
- For more information on sample to use Graph API in tab app, see the [hello-world-tab sample](https://github.com/OfficeDev/TeamsFx-Samples/tree/dev/hello-world-tab).
+ For more information on sample to use Graph API in tab app, see [hello-world-tab sample](https://github.com/OfficeDev/TeamsFx-Samples/tree/dev/hello-world-tab).
</details>
This section provides several code snippets for common scenarios that are relate
1. You can install the following required packages:
- ```bash
- npm install @microsoft/mgt-element @microsoft/mgt-teamsfx-provider @microsoft/teamsfx
- ```
+ ```bash
+ npm install @microsoft/mgt-element @microsoft/mgt-teamsfx-provider @microsoft/teamsfx
+ ```
2. Initialize the provider inside your component.
- ```typescript
- // Import the providers and credential at the top of the page
- import {Providers} from '@microsoft/mgt-element';
- import {TeamsFxProvider} from '@microsoft/mgt-teamsfx-provider';
- import {TeamsUserCredential} from "@microsoft/teamsfx";
-
- const scope = ["User.Read"];
- const teamsfx = new TeamsFx();
- const provider = new TeamsFxProvider(teamsfx, scope);
- Providers.globalProvider = provider;
- ```
+ ```typescript
+ // Import the providers and credential at the top of the page
+ import {Providers} from '@microsoft/mgt-element';
+ import {TeamsFxProvider} from '@microsoft/mgt-teamsfx-provider';
+ import {TeamsUserCredential} from "@microsoft/teamsfx";
+
+ const scope = ["User.Read"];
+ const teamsfx = new TeamsFx();
+ const provider = new TeamsFxProvider(teamsfx, scope);
+ Providers.globalProvider = provider;
+ ```
3. You can use the `teamsfx.login(scopes)` method to get required access token.
- ```typescript
- // Put these code in a call-to-action callback function to avoid browser blocking automatically showing up pop-ups.
- await teamsfx.login(this.scope);
- Providers.globalProvider.setState(ProviderState.SignedIn);
- ```
+ ```typescript
+ // Put these code in a call-to-action callback function to avoid browser blocking automatically showing up pop-ups.
+ await teamsfx.login(this.scope);
+ Providers.globalProvider.setState(ProviderState.SignedIn);
+ ```
- 4. You can now add any component in your HTML page or in your `render()` method with React to use the `TeamsFx` context to access Microsoft Graph.
+ 4. You can add any component in your HTML page or in your `render()` method with React to use the `TeamsFx` context to access Microsoft Graph.
- ```html
- <mgt-person query="me" view="threeLines"></mgt-person>
- ```
+ ```html
+ <mgt-person query="me" view="threeLines"></mgt-person>
+ ```
- ```typescript
- public render(): void {
- return (
+ ```typescript
+ public render(): void {
+ return (
<div> <Person personQuery="me" view={PersonViewType.threelines}></Person> </div>
- );
- }
- ```
+ );
+ }
+ ```
- For more information on sample to initialize the TeamsFx provider, see the [Contacts Exporter sample](https://github.com/OfficeDev/TeamsFx-Samples/tree/dev/graph-toolkit-contact-exporter).
+ For more information on sample to initialize the TeamsFx provider, see the [contacts exporter sample](https://github.com/OfficeDev/TeamsFx-Samples/tree/dev/graph-toolkit-contact-exporter).
</details>
-* User delegate permission in backend (Use OnBehalfOfUserCredential)
+* User delegate permission in backend (Use `OnBehalfOfUserCredential`)
<details> <summary><b>Use Graph API in bot Application</b></summary>
- This code snippet shows you how to use `TeamsBotSsoPrompt` to set a dialog and then sign-in to get an access token.
+ This code snippet shows you how to use `TeamsBotSsoPrompt` to set a dialog and then sign in to get an access token.
1. Initialize and add `TeamsBotSsoPrompt` to dialog set.
- ```typescript
- const { ConversationState, MemoryStorage } = require("botbuilder");
- const { DialogSet, WaterfallDialog } = require("botbuilder-dialogs");
- const { TeamsBotSsoPrompt } = require("@microsoft/teamsfx");
-
- const convoState = new ConversationState(new MemoryStorage());
- const dialogState = convoState.createProperty("dialogState");
- const dialogs = new DialogSet(dialogState);
-
- const teamsfx = new TeamsFx();
- dialogs.add(
- new TeamsBotSsoPrompt(teamsfx, "TeamsBotSsoPrompt", {
- scopes: ["User.Read"],
- })
- );
- ```
-
- 2. Begin the dialog and sign-in.
-
- ```typescript
- dialogs.add(
- new WaterfallDialog("taskNeedingLogin", [
- async (step) => {
- return await step.beginDialog("TeamsBotSsoPrompt");
- },
- async (step) => {
- const token = step.result;
- if (token) {
- // ... continue with task needing access token ...
- } else {
+ ```typescript
+ const { ConversationState, MemoryStorage } = require("botbuilder");
+ const { DialogSet, WaterfallDialog } = require("botbuilder-dialogs");
+ const { TeamsBotSsoPrompt, OnBehalfOfCredentialAuthConfig, TeamsBotSsoPromptSettings } = require("@microsoft/teamsfx");
+
+ const convoState = new ConversationState(new MemoryStorage());
+ const dialogState = convoState.createProperty("dialogState");
+ const dialogs = new DialogSet(dialogState);
+
+ const TeamsBotSsoPromptId = "TEAMS_BOT_SSO_PROMPT";
+
+ const settings: TeamsBotSsoPromptSettings = {
+ scopes: ["User.Read"],
+ timeout: 900000,
+ endOnInvalidMessage: true,
+ };
+
+ const authConfig: OnBehalfOfCredentialAuthConfig = {
+ authorityHost: process.env.M365_AUTHORITY_HOST,
+ clientId: process.env.M365_CLIENT_ID,
+ tenantId: process.env.M365_TENANT_ID,
+ clientSecret: process.env.M365_CLIENT_SECRET,
+ };
+ const loginUrl = process.env.INITIATE_LOGIN_ENDPOINT;
+ const ssoPrompt = new TeamsBotSsoPrompt(authConfig, loginUrl, TeamsBotSsoPromptId, settings);
+
+ dialogs.add(ssoPrompt);
+ ```
+
+ 2. Start the dialog and sign in.
+
+ ```typescript
+ dialogs.add(
+ new WaterfallDialog("taskNeedingLogin", [
+ async (step) => {
+ return await step.beginDialog("TeamsBotSsoPrompt");
+ },
+ async (step) => {
+ const token = step.result;
+ if (token) {
+ // ... continue with task needing access token ...
+ } else {
await step.context.sendActivity(`Sorry... We couldn't log you in. Try again later.`); return await step.endDialog();
- }
- },
- ])
- );
- ```
+ }
+ },
+ ])
+ );
+ ```
For more information on sample to use graph API in bot application, see [bot-sso sample](https://github.com/OfficeDev/TeamsFx-Samples/tree/dev/bot-sso).
This section provides several code snippets for common scenarios that are relate
<details> <summary><b>Use Graph API in Message Extension</b></summary>
- This code snippet shows you how to override `handleTeamsMessagingExtensionQuery` extends from `TeamsActivityHandler`, and use `handleMessageExtensionQueryWithToken` provided by TeamsFx sdk to sign-in to get an access token:
+ The following code snippet shows how to override `handleTeamsMessagingExtensionQuery` that extends from `TeamsActivityHandler`, and use `handleMessageExtensionQueryWithSSO` provided by TeamsFx SDK to sign in to get an access token:
```typescript
- public async handleTeamsMessagingExtensionQuery(context: TurnContext, query: any): Promise<any> {
- return await handleMessageExtensionQueryWithToken(context, null, 'User.Read',
+
+ const authConfig: OnBehalfOfCredentialAuthConfig = {
+ authorityHost: process.env.M365_AUTHORITY_HOST,
+ clientId: process.env.M365_CLIENT_ID,
+ tenantId: process.env.M365_TENANT_ID,
+ clientSecret: process.env.M365_CLIENT_SECRET,
+ };
+ const loginUrl = process.env.INITIATE_LOGIN_ENDPOINT;
+ public async handleTeamsMessagingExtensionQuery(context: TurnContext, query: any): Promise<any> {
+ return await handleMessageExtensionQueryWithSSO(context, authConfig, loginUrl, 'User.Read',
async (token: MessageExtensionTokenResponse) => { // ... continue to query with access token ... });
- }
+ }
``` For more information on sample to use graph API in message extension, see [message-extension-sso-sample](https://aka.ms/teamsfx-me-sso-sample).
This section provides several code snippets for common scenarios that are relate
This code snippet shows you how to implement `TeamsFxBotSsoCommandHandler` for command bot to call Microsoft API. ```typescript
- import { Activity, TurnContext } from "botbuilder";
- import {
+ import { Activity, TurnContext } from "botbuilder";
+ import {
CommandMessage, TriggerPatterns,
- TeamsFx,
- createMicrosoftGraphClient,
+ createMicrosoftGraphClientWithCredential,
TeamsFxBotSsoCommandHandler, TeamsBotSsoPromptTokenResponse,
- } from "@microsoft/teamsfx";
+ } from "@microsoft/teamsfx";
- export class ProfileSsoCommandHandler implements TeamsFxBotSsoCommandHandler {
+ const authConfig: OnBehalfOfCredentialAuthConfig = {
+ authorityHost: process.env.M365_AUTHORITY_HOST,
+ clientId: process.env.M365_CLIENT_ID,
+ tenantId: process.env.M365_TENANT_ID,
+ clientSecret: process.env.M365_CLIENT_SECRET,
+ };
+ const loginUrl = process.env.INITIATE_LOGIN_ENDPOINT;
+
+ export class ProfileSsoCommandHandler implements TeamsFxBotSsoCommandHandler {
triggerPatterns: TriggerPatterns = "profile"; async handleCommandReceived(
This section provides several code snippets for common scenarios that are relate
message: CommandMessage, tokenResponse: TeamsBotSsoPromptTokenResponse, ): Promise<string | Partial<Activity> | void> {
- // Init TeamsFx instance with SSO token
- const teamsfx = new TeamsFx().setSsoToken(tokenResponse.ssoToken);
+
+ const oboCredential = new OnBehalfOfUserCredential(tokenResponse.ssoToken, oboAuthConfig);
// Add scope for your Azure AD app. For example: Mail.Read, etc.
- const graphClient = createMicrosoftGraphClient(teamsfx, ["User.Read"]);
+ const graphClient = createMicrosoftGraphClientWithCredential(oboCredential, ["User.Read"]);
// Call graph api use `graph` instance to get user profile information const me = await graphClient.api("/me").get();
This section provides several code snippets for common scenarios that are relate
return "Could not retrieve profile information from Microsoft Graph."; } }
- }
- ```
+ }
- For more information about how to use this class in command bot, see [Add single sign-on to Teams app](add-single-sign-on.md). And there's also a [command-bot-with-sso](https://github.com/OfficeDev/TeamsFx-Samples/tree/dev/command-bot-with-sso) sample project, which you can try sso command bot.
+ ```
+
+ For more information about how to implement SSO command handler in command bot, see [add single sign-on to Teams app](add-single-sign-on.md). And there's a [command-bot-with-sso](https://github.com/OfficeDev/TeamsFx-Samples/tree/dev/command-bot-with-sso) sample project, that you can try SSO command bot.
</details> <details> <summary><b>Call Azure Function in tab app: On-Behalf-Of flow</b></summary>
- This code snippet shows you how to use `CreateApiClient` or `axios` library to call Azure Function, and how to call Graph API in Azure function to get user profiles.
+ This code snippet shows you how to use `CreateApiClient` or `axios` library to call Azure Function, and how to call Graph API in Azure Function to get user profiles.
1. You can use `CreateApiClient` provided by TeamsFx sdk to call Azure Function:
- ```typescript
- async function callFunction(teamsfx?: TeamsFx) {
- const teamsfx = new TeamsFx();
-
- // Get the credential.
- const credential = teamsfx.getCredential();
- // Create an API client by providing the token and endpoint.
- const apiClient = CreateApiClient(
- teamsfx.getConfig("YOUR_API_ENDPOINT"), // Create an API Client that uses SSO token to authenticate requests
- new BearerTokenAuthProvider(async () => (await credential.getToken(""))!.token) // Call API hosted in Azure Functions on behalf of user to inject token to request header
- );
-
- // Send a GET request to "RELATIVE_API_PATH", "/api/functionName" for example.
- const response = await apiClient.get("RELATIVE_API_PATH");
- return response.data;
- }
- ```
-
- You can also use `axios` library to call Azure Function.
-
- ```typescript
- async function callFunction(teamsfx?: TeamsFx) {
- const accessToken = await teamsfx.getCredential().getToken(""); // Get SSO token
- // teamsfx.getConfig("apiEndpoint") will read REACT_APP_FUNC_ENDPOINT environment variable
- const endpoint = teamsfx.getConfig("apiEndpoint");
- const response = await axios.default.get(endpoint + "/api/" + functionName, {
- headers: {
- authorization: "Bearer " + accessToken.token,
- },
- });
- return response.data;
- }
- ```
-
- 2. Call Graph API in Azure function on-behalf of user in response.
-
- ```typescript
- export default async function run(
- context: Context,
- req: HttpRequest,
- teamsfxContext: TeamsfxContext
- ): Promise<Response> {
- const res: Response = { status: 200, body: {},};
- // ...
- teamsfx = new TeamsFx().setSsoToken(accessToken);
- // Query user's information from the access token.
- try {
- const currentUser: UserInfo = await teamsfx.getUserInfo();
- if (currentUser && currentUser.displayName) {
- res.body.userInfoMessage = `User display name is ${currentUser.displayName}.`;
- } else {
- res.body.userInfoMessage = "No user information was found in access token.";
+ ```typescript
+ async function callFunction() {
+ const authConfig: TeamsUserCredentialAuthConfig = {
+ clientId: process.env.REACT_APP_CLIENT_ID,
+ initiateLoginEndpoint: process.env.REACT_APP_START_LOGIN_PAGE_URL,
+ };
+ const teamsUserCredential = new TeamsUserCredential(authConfig);
+ // Create an API client by providing the token and endpoint.
+ const apiClient = CreateApiClient(
+ "https://YOUR_API_ENDPOINT", // Create an API Client that uses SSO token to authenticate requests
+ new BearerTokenAuthProvider(async () => (await teamsUserCredential.getToken(""))!.token) // Call API hosted in Azure Functions on behalf of user to inject token to request header
+ );
+ // Send a GET request to "RELATIVE_API_PATH", "/api/functionName" for example.
+ const response = await apiClient.get("RELATIVE_API_PATH");
+ return response.data;
+ }
+ ```
+
+ You can also use `axios` library to call Azure Function.
+
+ ```typescript
+ async function callFunction() {
+ const authConfig: TeamsUserCredentialAuthConfig = {
+ clientId: process.env.REACT_APP_CLIENT_ID,
+ initiateLoginEndpoint: process.env.REACT_APP_START_LOGIN_PAGE_URL,
+ };
+ const teamsUserCredential = new TeamsUserCredential(authConfig);
+ const accessToken = await teamsUserCredential.getToken(""); // Get SSO token
+ const endpoint = "https://YOUR_API_ENDPOINT";
+ const response = await axios.default.get(endpoint + "/api/" + functionName, {
+ headers: {
+ authorization: "Bearer " + accessToken.token,
+ },
+ });
+ return response.data;
+ }
+
+ ```
+
+ 2. Call Graph API in Azure Function on-behalf of user in response.
+
+ ```typescript
+
+ export default async function run(
+ context: Context,
+ req: HttpRequest,
+ teamsfxContext: TeamsfxContext
+ ): Promise<Response> {
+ const res: Response = { status: 200, body: {},};
+
+ const authConfig: OnBehalfOfCredentialAuthConfig = {
+ authorityHost: process.env.M365_AUTHORITY_HOST,
+ clientId: process.env.M365_CLIENT_ID,
+ tenantId: process.env.M365_TENANT_ID,
+ clientSecret: process.env.M365_CLIENT_SECRET,
+ };
+ const oboCredential = new OnBehalfOfUserCredential(tokenResponse.ssoToken, oboAuthConfig);
+
+ // Query user's information from the access token.
+ try {
+ const currentUser: UserInfo = await oboCredential.getUserInfo();
+ if (currentUser && currentUser.displayName) {
+ res.body.userInfoMessage = `User display name is ${currentUser.displayName}.`;
+ } else {
+ res.body.userInfoMessage = "No user information was found in access token.";
+ }
+ } catch (e) {
}
- } catch (e) {
- }
- // Create a graph client to access user's Microsoft 365 data after user has consented.
- try {
- const graphClient: Client = createMicrosoftGraphClient(teamsfx, [".default"]);
- const profile: any = await graphClient.api("/me").get();
- res.body.graphClientMessage = profile;
- } catch (e) {
- }
- return res;
- }
- ```
+ // Create a graph client to access user's Microsoft 365 data after user has consented.
+ try {
+ const graphClient: Client = createMicrosoftGraphClientWithCredential(oboCredential, [".default"]);
+ const profile: any = await graphClient.api("/me").get();
+ res.body.graphClientMessage = profile;
+ } catch (e) {
+ }
+ return res;
+ }
+
+ ```
For more information on sample to use graph API in bot application, see [hello-world-tab-with-backend sample](https://github.com/OfficeDev/TeamsFx-Samples/tree/dev/hello-world-tab-with-backend).
This section provides several code snippets for common scenarios that are relate
This code snippet shows you how to use certificate-based application permission to get the token that can be used to call Graph API.
- 1. You can initialize the `authConfig` by providing a `PEM-encoded key certificate`.
+ 1. You can initialize the `appAuthConfig` by providing a `PEM-encoded key certificate`.
- ```typescript
- const authConfig = {
- clientId: process.env.M365_CLIENT_ID,
- certificateContent: "The content of a PEM-encoded public/private key certificate",
- authorityHost: process.env.M365_AUTHORITY_HOST,
- tenantId: process.env.M365_TENANT_ID,
- };
- ```
+ ```typescript
+ const appAuthConfig: AppCredentialAuthConfig = {
+ authorityHost: process.env.M365_AUTHORITY_HOST,
+ clientId: process.env.M365_CLIENT_ID,
+ tenantId: process.env.M365_TENANT_ID,
+ certificateContent: 'PEM-encoded key certificate',
+ };
- 2. You can use the `authConfig` to get the token.
+ ```
- ```typescript
- const teamsfx = new TeamsFx(IdentityType.App);
- teamsfx.setCustomeConfig(authConfig);
- const token = teamsfx.getCredential().getToken();
- ```
+ 2. You can use the `AppCredential` to get the token.
+
+ ```typescript
+ const appCredential = new AppCredential(appAuthConfig);
+ const token = appCredential.getToken();
+ ```
</details>
This section provides several code snippets for common scenarios that are relate
1. You can initialize the `authConfig` by providing a `client secret`.
- ```typescript
- const authConfig = {
- clientId: process.env.M365_CLIENT_ID,
- clientSecret: process.env.M365_CLIENT_SECRET,
- authorityHost: process.env.M365_AUTHORITY_HOST,
- tenantId: process.env.M365_TENANT_ID,
- };
- ```
+ ```typescript
+ const appAuthConfig: AppCredentialAuthConfig = {
+ authorityHost: process.env.M365_AUTHORITY_HOST,
+ clientId: process.env.M365_CLIENT_ID,
+ tenantId: process.env.M365_TENANT_ID,
+ clientSecret: process.env.M365_CLIENT_SECRET,
+ };
+ ```
2. You can use the `authConfig` to get the token.
- ```typescript
- const teamsfx = new TeamsFx(IdentityType.App);
- teamsfx.setCustomeConfig(authConfig);
- const token = teamsfx.getCredential().getToken();
- ```
+ ```typescript
+ const appCredential = new AppCredential(appAuthConfig);
+ const token = appCredential.getToken();
+ ```
For more information on sample to use graph API in bot application, see the [hello-world-tab-with-backend sample](https://github.com/OfficeDev/TeamsFx-Samples/tree/dev/hello-world-tab-with-backend).
This section provides several code snippets for other scenarios that are related
This code snippet shows you how to call an existing API in Bot by `ApiKeyProvider`. ```typescript
- const teamsfx = new TeamsFx();
- // Create an API Key auth provider. In addition to APiKeyProvider, following auth providers are also available: // BearerTokenAuthProvider, BasicAuthProvider, CertificateAuthProvider. const authProvider = new ApiKeyProvider("YOUR_API_KEY_NAME",
- teamsfx.getConfig("YOUR_API_KEY_VALUE"), // This reads the value of YOUR_API_KEY_VALUE environment variable.
+ "YOUR_API_KEY_VALUE",
ApiKeyLocation.Header ); // Create an API client using above auth provider. // You can also implement AuthProvider interface and use it here. const apiClient = createApiClient(
- teamsfx.getConfig("YOUR_API_ENDPOINT"), // This reads YOUR_API_ENDPOINT environment variable.
+ "YOUR_API_ENDPOINT",
authProvider );
This section provides several code snippets for other scenarios that are related
1. Set the connection configuration.
- ```typescript
- // Equivalent to:
- // const sqlConnectConfig = new DefaultTediousConnectionConfiguration({
- // sqlServerEndpoint: process.env.SQL_ENDPOINT,
- // sqlUsername: process.env.SQL_USER_NAME,
- // sqlPassword: process.env.SQL_PASSWORD,
- // });
- const teamsfx = new TeamsFx();
- // If there's only one SQL database
- const config = await getTediousConnectionConfig(teamsfx);
- // If there are multiple SQL databases
- const config2 = await getTediousConnectionConfig(teamsfx, "your database name");
- ```
+ ```typescript
+ // Equivalent to:
+ // const sqlConnectConfig = new DefaultTediousConnectionConfiguration({
+ // sqlServerEndpoint: process.env.SQL_ENDPOINT,
+ // sqlUsername: process.env.SQL_USER_NAME,
+ // sqlPassword: process.env.SQL_PASSWORD,
+ // });
+ const teamsfx = new TeamsFx();
+ // If there's only one SQL database
+ const config = await getTediousConnectionConfig(teamsfx);
+ // If there are multiple SQL databases
+ const config2 = await getTediousConnectionConfig(teamsfx, "your database name");
+ ```
2. Connect to your database.
- ```typescript
- const connection = new Connection(config);
- connection.on("connect", (error) => {
- if (error) {
+ ```typescript
+ const connection = new Connection(config);
+ connection.on("connect", (error) => {
+ if (error) {
console.log(error);
- }
- });
- ```
+ }
+ });
+ ```
> [!NOTE]
- > For more information on sample to access SQL database in Azure function, see [share-now sample](https://github.com/OfficeDev/TeamsFx-Samples/tree/dev/share-now).
+ > For more information on sample to access SQL database in Azure Function, see [share-now sample](https://github.com/OfficeDev/TeamsFx-Samples/tree/dev/share-now). The `getTediousConnectionConfig` function has been deprecated, we recommend you to compose your own tedious configuration for better flexibility.
</details>
This section provides several code snippets for other scenarios that are related
You can set customer log level and redirect outputs when using this library. > [!NOTE]
-> Logging is turned off by default, you can turn it on by setting log level.
+> Logs is turned off by default, you can turn it on by setting log level.
#### Enable log by setting log level