Using the "Hello World" Microsoft Teams application sample from here: https://github.com/OfficeDev/msteams-samples-hello-world-csharp
Trying to get a list of participants in a personal Microsoft Teams 1:1 chat after an action command from a messaging extension is invoked. Specifically, I need the e-mail address of the other participant, where I am the first participant.
This is the code from the messages controller:
[BotAuthentication]
public class MessagesController : ApiController
{
[HttpPost]
public async Task<HttpResponseMessage> Post([FromBody] Activity activity)
{
using (var connector = new ConnectorClient(new Uri(activity.ServiceUrl)))
{
if (activity.IsComposeExtensionQuery())
{
// Invoke the command handler
var response = await MessageExtension.HandleMessageExtensionQuery(connector, activity).ConfigureAwait(false);
return response != null
? Request.CreateResponse<ComposeExtensionResponse>(response)
: new HttpResponseMessage(HttpStatusCode.OK);
}
else
{
await EchoBot.EchoMessage(connector, activity);
return new HttpResponseMessage(HttpStatusCode.Accepted);
}
}
}
}
The code from MessageExtension.HandleMessageExtensionQuery
is as follows:
public static async Task<ComposeExtensionResponse> HandleMessageExtensionQuery(ConnectorClient connector, Activity activity)
{
var query = activity.GetComposeExtensionQueryData();
if (query == null)
{
return null;
}
// Exception thrown here - error 403, there is no additional data except "Operation returned an invalid status code 'Forbidden'"
var members = await connector.Conversations.GetConversationMembersAsync(activity.Conversation.Id);
var handler = GetCommandHandler(query.CommandId); // Gets a handler based on the command, irrelevant for this question
if (handler == null)
{
return null;
}
return await handler.HandleCommand(query, members); // Should handle the command, but never comes here if we are in a 1:1 conversation
}
The call to GetConversationMembersAsync
fails with the following message: Operation returned an invalid status code 'Forbidden'
if the command is invoked from a 1:1 personal conversation between two people.
The call doesn't fail if invoked from a group channel.
How to get the list of participants of a 1:1 personal conversation? Do I have to authenticate my user through the bot in order to do that, or do I have to grant my bot some particular permissions? Does my account need to have some particular permissions in order to do this?
EDIT - Added the app manifest
{
"$schema": "https://developer.microsoft.com/en-us/json-schemas/teams/v1.5/MicrosoftTeams.schema.json",
"manifestVersion": "1.5",
"version": "1.0.0",
"id": "1ce95960-0417-4469-ab77-5052758a4e7e",
"packageName": "com.contoso.helloworld",
"developer": {
"name": "Contoso",
"websiteUrl": "https://8112abe3.ngrok.io",
"privacyUrl": "https://8112abe3.ngrok.io/privacy-policy",
"termsOfUseUrl": "https://8112abe3.ngrok.io/terms-service"
},
"icons": {
"color": "color.png",
"outline": "outline.png"
},
"name": {
"short": "Hello World",
"full": "Hello World App"
},
"description": {
"short": "Hello World App for Microsoft Teams",
"full": "This sample app provides a very simple app. You can extend this to add more content and capabilities."
},
"accentColor": "#60A18E",
"configurableTabs": [
{
"configurationUrl": "https://526d7c43.ngrok.io/configure",
"canUpdateConfiguration": true,
"scopes": [
"team",
"groupchat"
]
}
],
"staticTabs": [
{
"entityId": "com.contoso.helloworld.hellotab",
"name": "Hello Tab",
"contentUrl": "https://8112abe3.ngrok.io/hello",
"websiteUrl": "https://8112abe3.ngrok.io/hello",
"scopes": [
"personal"
]
}
],
"bots": [
{
"botId": "bfbcb607-5c29-4438-85a5-15e63fb0b273",
"scopes": [
"personal",
"team",
"groupchat"
],
"supportsFiles": false,
"isNotificationOnly": false
}
],
"composeExtensions": [
{
"botId": "bfbcb607-5c29-4438-85a5-15e63fb0b273",
"canUpdateConfiguration": true,
"commands": [
{
"id": "getRandomText",
"type": "query",
"title": "Get random text",
"description": "",
"initialRun": true,
"fetchTask": false,
"context": [
"commandBox",
"compose",
"message"
],
"parameters": [
{
"name": "cardTitle",
"title": "Subject",
"description": "",
"inputType": "text"
}
]
}
]
}
],
"permissions": [
"identity",
"messageTeamMembers"
],
"validDomains": [
"8112abe3.ngrok.io"
]
}
EDIT 2 - After trying, based on sample 51 - TeamsMessagingExtensionsAction
As suggested, I tried with the sample 51 called "TeamsMessagingExtensionsAction" The code is:
MicrosoftAppCredentials.TrustServiceUrl(turnContext.Activity.ServiceUrl);
var members = (await turnContext.TurnState.Get<IConnectorClient>().Conversations.GetConversationMembersAsync(
turnContext.Activity.Conversation.Id).ConfigureAwait(false)).ToList();
The exception along with the stack trace:
Microsoft.Bot.Schema.ErrorResponseException: Operation returned an invalid status code 'Forbidden'
at Microsoft.Bot.Connector.Conversations.GetConversationMembersWithHttpMessagesAsync(String conversationId, Dictionary`2 customHeaders, CancellationToken cancellationToken) in d:\a\1\s\libraries\Microsoft.Bot.Connector\Conversations.cs:line 1462
at Microsoft.BotBuilderSamples.Bots.TeamsMessagingExtensionsActionBot.ShareMessageCommand(ITurnContext`1 turnContext, MessagingExtensionAction action) in D:\Visual Studio Projects\botbuilder-samples\samples\csharp_dotnetcore\51.teams-messaging-extensions-action\Bots\TeamsMessagingExtensionsActionBot.cs:line 68
at Microsoft.BotBuilderSamples.Bots.TeamsMessagingExtensionsActionBot.OnTeamsMessagingExtensionSubmitActionAsync(ITurnContext`1 turnContext, MessagingExtensionAction action, CancellationToken cancellationToken) in D:\Visual Studio Projects\botbuilder-samples\samples\csharp_dotnetcore\51.teams-messaging-extensions-action\Bots\TeamsMessagingExtensionsActionBot.cs:line 29
at Microsoft.Bot.Builder.Teams.TeamsActivityHandler.OnTeamsMessagingExtensionSubmitActionDispatchAsync(ITurnContext`1 turnContext, MessagingExtensionAction action, CancellationToken cancellationToken) in d:\a\1\s\libraries\Microsoft.Bot.Builder\Teams\TeamsActivityHandler.cs:line 201
at Microsoft.Bot.Builder.Teams.TeamsActivityHandler.OnInvokeActivityAsync(ITurnContext`1 turnContext, CancellationToken cancellationToken) in d:\a\1\s\libraries\Microsoft.Bot.Builder\Teams\TeamsActivityHandler.cs:line 88
at Microsoft.Bot.Builder.Teams.TeamsActivityHandler.OnTurnAsync(ITurnContext turnContext, CancellationToken cancellationToken) in d:\a\1\s\libraries\Microsoft.Bot.Builder\Teams\TeamsActivityHandler.cs:line 39
at Microsoft.Bot.Builder.BotFrameworkAdapter.TenantIdWorkaroundForTeamsMiddleware.OnTurnAsync(ITurnContext turnContext, NextDelegate next, CancellationToken cancellationToken) in d:\a\1\s\libraries\Microsoft.Bot.Builder\BotFrameworkAdapter.cs:line 1158
at Microsoft.Bot.Builder.MiddlewareSet.ReceiveActivityWithStatusAsync(ITurnContext turnContext, BotCallbackHandler callback, CancellationToken cancellationToken) in d:\a\1\s\libraries\Microsoft.Bot.Builder\MiddlewareSet.cs:line 55
at Microsoft.Bot.Builder.BotAdapter.RunPipelineAsync(ITurnContext turnContext, BotCallbackHandler callback, CancellationToken cancellationToken) in d:\a\1\s\libraries\Microsoft.Bot.Builder\BotAdapter.cs:line 182
EDIT 3 - Tried with the sample 57
So I have started with the sample 57 called "TeamsConversationBot" and TLDR; works in channel, doesn't work in a private conversation.
Here are the steps performed:
Note: ngrok was already started using the command ngrok http -host-header=rewrite 3978
and my existing bot registration was already configured to listen on the given URL
- Updated the appsettings.json configuration for the project to use the Microsoft App Id and App Password from the Bot Framework registration.
- Edited the manifest.json contained in the TeamsAppManifest with the required GUIDs, zipped it along with PNG icons into manifest.zip and uploaded to Teams App Studio using "Import an existing app", which resulted in a new application called "TeamsConversationBot"
- In Teams App Studio, opened the new application for editing, went to "Test and distribute", clicked "Install" and then "Add" on the next screen.
- Navigated to the above screen again, but instead of "Add" I chose "Add to a team" from the drop down, where I added the bot to the channel of the Team I am the owner of.
- In Visual Studio, went to TeamsConversationsBot.cs and set a breakpoint in MessageAllMembersAsync method, on a line which says
var members = await TeamsInfo.GetMembersAsync(turnContext, cancellationToken);
- Started the project, went to my channel in Teams, sent the "MessageAllMembers" to my bot, waited for the above mentioned breakpoint to be hit and observed that the said call succeeds, i.e. returns a list of members. So far so good!
- Went back to Teams App Builder to edit my "TeamsConversationsBot" app.
- In manifest editor, went to "Messaging extensions" tab and set up my existing bot to listen for messaging extension invocations.
- Added a new action-based command with a defined number of parameters. Gave it an Id, named a parameter and input the other mandatory fields, doesn't really matter. For "select the context in which the compose extension should work" I chose "Command Box" and "Compose Box", ticked "Initial run" and clicked "Save".
- Installed the app again using "Test and distribute" -> "Install" and then "Add" button.
In Visual Studio, added the following method to TeamsConversationBot.cs:
protected override async Task<InvokeResponse> OnInvokeActivityAsync(ITurnContext<IInvokeActivity> turnContext, CancellationToken cancellationToken) { var connector = turnContext.TurnState.Get<IConnectorClient>(); var conversation = turnContext.Activity.Conversation; var members = await connector.Conversations.GetConversationMembersAsync(conversation.Id, cancellationToken); return await base.OnInvokeActivityAsync(turnContext, cancellationToken); }
Set a breakpoint on the line which says
var members = await connector.Conversations.GetConversationMembersAsync(conversation.Id, cancellationToken);
and start the project- Went to the channel, selected messaging extensions under the compose box and invoked the newly added command. This triggered the above breakpoint to be hit. Performed a step over and observed that
members
variable contained all members of the channel. So that works too! - Went to a private conversation between me and the other team member (where me and them both have sent messages to each other previously, to ensure the conversation is not empty), selected messaging extensions under the compose box and invoked the newly added command. This again triggered the above mentioned breakpoint to be hit. Performed a step over and bam! The call has caused an unhandled exception
Microsoft.Bot.Schema.ErrorResponseException: Operation returned an invalid status code 'Forbidden'