为 1:1 私人对话调用 GetConversationMembersAsync 时,操作返回无效状态代码 'Forbidden'
Operation returned an invalid status code 'Forbidden' when calling GetConversationMembersAsync for 1:1 private conversation
使用此处的 "Hello World" Microsoft Teams 应用程序示例:https://github.com/OfficeDev/msteams-samples-hello-world-csharp
在调用来自消息扩展的操作命令后,尝试获取个人 Microsoft Teams 1:1 聊天的参与者列表。具体来说,我需要其他参与者的电子邮件地址,我是第一个参与者。
这是来自消息控制器的代码:
[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);
}
}
}
}
来自MessageExtension.HandleMessageExtensionQuery
的代码如下:
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
}
调用 GetConversationMembersAsync
失败并显示以下消息:Operation returned an invalid status code 'Forbidden'
如果命令是从两个人之间的 1:1 个人对话中调用的。
如果从群组频道调用,调用不会失败。
如何获取1:1个人对话的参与者列表?我是否必须通过机器人对我的用户进行身份验证才能执行此操作,或者我是否必须授予我的机器人一些特定权限?我的帐户是否需要某些特定权限才能执行此操作?
编辑 - 添加了应用清单
{
"$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"
]
}
编辑 2 - 尝试后,基于示例 51 - TeamsMessagingExtensionsAction
按照建议,我尝试使用 sample 51 called "TeamsMessagingExtensionsAction"
密码是:
MicrosoftAppCredentials.TrustServiceUrl(turnContext.Activity.ServiceUrl);
var members = (await turnContext.TurnState.Get<IConnectorClient>().Conversations.GetConversationMembersAsync(
turnContext.Activity.Conversation.Id).ConfigureAwait(false)).ToList();
异常以及堆栈跟踪:
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\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.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.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\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\s\libraries\Microsoft.Bot.Builder\Teams\TeamsActivityHandler.cs:line 88
at Microsoft.Bot.Builder.Teams.TeamsActivityHandler.OnTurnAsync(ITurnContext turnContext, CancellationToken cancellationToken) in d:\a\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\s\libraries\Microsoft.Bot.Builder\BotFrameworkAdapter.cs:line 1158
at Microsoft.Bot.Builder.MiddlewareSet.ReceiveActivityWithStatusAsync(ITurnContext turnContext, BotCallbackHandler callback, CancellationToken cancellationToken) in d:\a\s\libraries\Microsoft.Bot.Builder\MiddlewareSet.cs:line 55
at Microsoft.Bot.Builder.BotAdapter.RunPipelineAsync(ITurnContext turnContext, BotCallbackHandler callback, CancellationToken cancellationToken) in d:\a\s\libraries\Microsoft.Bot.Builder\BotAdapter.cs:line 182
编辑 3 - 尝试使用示例 57
所以我开始使用 sample 57 called "TeamsConversationBot" 和 TLDR;在频道中有效,在私人对话中无效。
执行的步骤如下:
注意:ngrok 已使用命令 ngrok http -host-header=rewrite 3978
启动,并且我现有的机器人注册已配置为侦听给定的 URL
- 更新了项目的 appsettings.json 配置,以使用来自 Bot Framework 注册的 Microsoft App Id 和 App Password。
- 使用所需的 GUID 编辑 TeamsAppManifest 中包含的 manifest.json,将其与 PNG 图标一起压缩到 manifest.zip 并使用“导入现有应用程序上传到 Teams App Studio ”,这导致了一个名为 "TeamsConversationBot"
的新应用程序
- 在 Teams App Studio 中,打开新的应用程序进行编辑,转到“测试和分发”,单击“安装”,然后然后在下一个屏幕上“添加”。
- 再次导航到上面的屏幕,但我从下拉列表中选择了“添加到团队”而不是“添加” ,我将机器人添加到我拥有的团队的频道中。
- 在Visual Studio中,转到TeamsConversationsBot.cs并在MessageAllMembersAsync方法中设置断点,在一行它说
var members = await TeamsInfo.GetMembersAsync(turnContext, cancellationToken);
- 启动项目,转到我在 Teams 中的频道,将“MessageAllMembers”发送到我的机器人,等待命中上述断点并观察到上述调用成功,即 returns 成员列表。 目前一切顺利!
- 返回 Teams App Builder 编辑我的 "TeamsConversationsBot" 应用程序。
- 在清单编辑器中,转到 "Messaging extensions" 选项卡并设置我现有的机器人来侦听消息扩展调用。
- 添加了一个新的基于操作的命令,该命令具有定义数量的参数。给它一个 Id,命名一个参数并输入其他必填字段,并不重要。对于"select the context in which the compose extension should work",我选择了“命令框”和“撰写框”,勾选了“初始运行”并单击“保存”。
- 使用“测试和分发”再次安装应用程序 -> “安装”然后“添加" 按钮。
在Visual Studio中,在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);
}
在显示 var members = await connector.Conversations.GetConversationMembersAsync(conversation.Id, cancellationToken);
的行上设置断点并启动项目
- 进入频道,在撰写框下选择消息扩展并调用新添加的命令。这触发了上面的断点。执行了一步并观察到
members
变量包含通道的所有成员。 这样也行!
- 进入我和其他团队成员之间的私人对话(我和他们之前都互相发送过消息,以确保对话不为空),在撰写框下选择消息扩展并调用新添加的命令。这再次触发了上述断点。执行了一步并且 bam! 调用导致了未处理的异常
Microsoft.Bot.Schema.ErrorResponseException: Operation returned an invalid status code 'Forbidden'
回复编辑 3
抱歉,我好像误解了你的意思。您不能使用 Bot Framework 执行此操作。从技术上讲,该机器人不是您与其他用户之间个人对话的一部分。因此,它没有权限获取有关该对话的信息,即使它可以作为消息传递扩展程序使用。
您可以使用 this Graph API call,但您必须自己处理获取授权令牌的问题:
https://graph.microsoft.com/beta/chats/<conversationId>/members
将其作为答案是因为评论太长了,我认为它应该可以满足您的需求。请让我知道这是否有效,我可以编辑此
通过查看您的 appId
,我在后端没有看到任何东西,所以我不确定问题的真正原因是什么。
您根本不需要设置任何权限——那些仅适用于 OAuth,GetConversationMembersAsync
不需要。您应该只真正需要 manifest.json
中设置的范围,这些范围似乎设置得很好。
但是,对于您的应用程序注册,您可能需要确保在身份验证下选中此项:
如果不是,您可以手动调整您的应用程序注册的清单,设置如下:
"signInAudience": "AzureADandPersonalMicrosoftAccount",
如果 none 有效:
请尝试使用当前的 BotFramework SDK 实现相同功能的 Sample 57, which has a GetMembersAsync
功能。请确保遵循自述文件并按照指定设置所有内容。
让我知道进展如何。如果您需要额外的帮助,您能否尝试尽可能详细地解释您的复制步骤?我想尝试重现这一点,并希望确保我们的步骤匹配——它也可以帮助我找出你可能出错的地方。
实际上,在调用基于操作的消息传递扩展时,有一种方法可以获取两人之间 1:1 私人对话的参与者列表。诀窍是让机器人也进入私人对话。
我一开始也想过这个解决方案,但不知道如何解决,而且没有人建议,我认为不可能一蹴而就。但事实证明我错了。
万一有人遇到这种问题。在这里。
最初我使用 FetchTask 动作消息扩展(基于动作的消息扩展,您不提供预定义的参数列表,而是使用机器人获取参数)。
但它也可以使用带有静态参数的常规操作来完成,所以让我们使用我在问题中使用的方法 OnInvokeActivityAsync
来做一个例子。请参阅下面代码中的注释以获取解释。
protected override async Task<InvokeResponse> OnInvokeActivityAsync(ITurnContext<IInvokeActivity> turnContext, CancellationToken cancellationToken)
{
var connector = turnContext.TurnState.Get<IConnectorClient>();
var conversation = turnContext.Activity.Conversation;
IList<ChannelAccount> members;
try
{
members = await connector.Conversations.GetConversationMembersAsync(conversation.Id, cancellationToken);
}
catch (ErrorResponseException ex)
{
// If the ErrorResponseException contains the response with status code 403, that means our bot is not a member of this conversation.
// In that case, return an adaptive card containing the prompt to add the bot to the current conversation.
// After accepting the prompt, the bot will be added to the conversation and we will be able to obtain the list of conversation participants.
if (ex.Response.StatusCode == HttpStatusCode.Forbidden)
{
return new InvokeResponse
{
Status = 200,
Body = AddBotToConversation()
};
}
throw;
}
// At this point, we have the list of conversation members
var otherMember = members.FirstOrDefault(x => x.Id != turnContext.Activity.From.Id);
return new InvokeResponse
{
Status = 200,
Body = await DoSomethingWithOtherMemberInformationAndReturnACard(otherMember, cancellationToken)
};
}
AddBotToConversation
可以这样定义:
private MessagingExtensionActionResponse AddBotToConversation()
{
var card = new AdaptiveCard(new AdaptiveSchemaVersion(1, 0))
{
Body = new List<AdaptiveElement>()
{
new AdaptiveTextBlock("We need to add the bot to this conversation in order to perform the requested action"),
},
Actions = new List<AdaptiveAction>()
{
new AdaptiveSubmitAction
{
Title = "Continue",
Data = new Dictionary<string, object>
{
// The magic happens here. This tells Teams to add this bot to the current conversation
["msteams"] = new Dictionary<string, bool>
{
["justInTimeInstall"] = true,
}
}
}
}
};
var invokeResponse = new MessagingExtensionActionResponse
{
Task = new TaskModuleContinueResponse
{
Value = new TaskModuleTaskInfo
{
Card = new Attachment
{
ContentType = AdaptiveCard.ContentType,
Content = card
}
}
}
};
return invokeResponse;
}
只需确保消息扩展是基于操作的,而不是基于搜索的。搜索扩展将不支持这种方法。
EDIT 最后但同样重要的是,不要忘记将 "groupchat"
范围添加到 [=16] 下机器人的 "scopes"
集合中=] 集合在 Teams 应用程序 manifest.json 文件中,否则您将无法将您的机器人添加到私人对话中。
使用此处的 "Hello World" Microsoft Teams 应用程序示例:https://github.com/OfficeDev/msteams-samples-hello-world-csharp
在调用来自消息扩展的操作命令后,尝试获取个人 Microsoft Teams 1:1 聊天的参与者列表。具体来说,我需要其他参与者的电子邮件地址,我是第一个参与者。
这是来自消息控制器的代码:
[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);
}
}
}
}
来自MessageExtension.HandleMessageExtensionQuery
的代码如下:
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
}
调用 GetConversationMembersAsync
失败并显示以下消息:Operation returned an invalid status code 'Forbidden'
如果命令是从两个人之间的 1:1 个人对话中调用的。
如果从群组频道调用,调用不会失败。
如何获取1:1个人对话的参与者列表?我是否必须通过机器人对我的用户进行身份验证才能执行此操作,或者我是否必须授予我的机器人一些特定权限?我的帐户是否需要某些特定权限才能执行此操作?
编辑 - 添加了应用清单
{
"$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"
]
}
编辑 2 - 尝试后,基于示例 51 - TeamsMessagingExtensionsAction
按照建议,我尝试使用 sample 51 called "TeamsMessagingExtensionsAction" 密码是:
MicrosoftAppCredentials.TrustServiceUrl(turnContext.Activity.ServiceUrl);
var members = (await turnContext.TurnState.Get<IConnectorClient>().Conversations.GetConversationMembersAsync(
turnContext.Activity.Conversation.Id).ConfigureAwait(false)).ToList();
异常以及堆栈跟踪:
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\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.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.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\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\s\libraries\Microsoft.Bot.Builder\Teams\TeamsActivityHandler.cs:line 88
at Microsoft.Bot.Builder.Teams.TeamsActivityHandler.OnTurnAsync(ITurnContext turnContext, CancellationToken cancellationToken) in d:\a\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\s\libraries\Microsoft.Bot.Builder\BotFrameworkAdapter.cs:line 1158
at Microsoft.Bot.Builder.MiddlewareSet.ReceiveActivityWithStatusAsync(ITurnContext turnContext, BotCallbackHandler callback, CancellationToken cancellationToken) in d:\a\s\libraries\Microsoft.Bot.Builder\MiddlewareSet.cs:line 55
at Microsoft.Bot.Builder.BotAdapter.RunPipelineAsync(ITurnContext turnContext, BotCallbackHandler callback, CancellationToken cancellationToken) in d:\a\s\libraries\Microsoft.Bot.Builder\BotAdapter.cs:line 182
编辑 3 - 尝试使用示例 57
所以我开始使用 sample 57 called "TeamsConversationBot" 和 TLDR;在频道中有效,在私人对话中无效。
执行的步骤如下:
注意:ngrok 已使用命令 ngrok http -host-header=rewrite 3978
启动,并且我现有的机器人注册已配置为侦听给定的 URL
- 更新了项目的 appsettings.json 配置,以使用来自 Bot Framework 注册的 Microsoft App Id 和 App Password。
- 使用所需的 GUID 编辑 TeamsAppManifest 中包含的 manifest.json,将其与 PNG 图标一起压缩到 manifest.zip 并使用“导入现有应用程序上传到 Teams App Studio ”,这导致了一个名为 "TeamsConversationBot" 的新应用程序
- 在 Teams App Studio 中,打开新的应用程序进行编辑,转到“测试和分发”,单击“安装”,然后然后在下一个屏幕上“添加”。
- 再次导航到上面的屏幕,但我从下拉列表中选择了“添加到团队”而不是“添加” ,我将机器人添加到我拥有的团队的频道中。
- 在Visual Studio中,转到TeamsConversationsBot.cs并在MessageAllMembersAsync方法中设置断点,在一行它说
var members = await TeamsInfo.GetMembersAsync(turnContext, cancellationToken);
- 启动项目,转到我在 Teams 中的频道,将“MessageAllMembers”发送到我的机器人,等待命中上述断点并观察到上述调用成功,即 returns 成员列表。 目前一切顺利!
- 返回 Teams App Builder 编辑我的 "TeamsConversationsBot" 应用程序。
- 在清单编辑器中,转到 "Messaging extensions" 选项卡并设置我现有的机器人来侦听消息扩展调用。
- 添加了一个新的基于操作的命令,该命令具有定义数量的参数。给它一个 Id,命名一个参数并输入其他必填字段,并不重要。对于"select the context in which the compose extension should work",我选择了“命令框”和“撰写框”,勾选了“初始运行”并单击“保存”。
- 使用“测试和分发”再次安装应用程序 -> “安装”然后“添加" 按钮。
在Visual Studio中,在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); }
在显示
var members = await connector.Conversations.GetConversationMembersAsync(conversation.Id, cancellationToken);
的行上设置断点并启动项目- 进入频道,在撰写框下选择消息扩展并调用新添加的命令。这触发了上面的断点。执行了一步并观察到
members
变量包含通道的所有成员。 这样也行! - 进入我和其他团队成员之间的私人对话(我和他们之前都互相发送过消息,以确保对话不为空),在撰写框下选择消息扩展并调用新添加的命令。这再次触发了上述断点。执行了一步并且 bam! 调用导致了未处理的异常
Microsoft.Bot.Schema.ErrorResponseException: Operation returned an invalid status code 'Forbidden'
回复编辑 3
抱歉,我好像误解了你的意思。您不能使用 Bot Framework 执行此操作。从技术上讲,该机器人不是您与其他用户之间个人对话的一部分。因此,它没有权限获取有关该对话的信息,即使它可以作为消息传递扩展程序使用。
您可以使用 this Graph API call,但您必须自己处理获取授权令牌的问题:
https://graph.microsoft.com/beta/chats/<conversationId>/members
将其作为答案是因为评论太长了,我认为它应该可以满足您的需求。请让我知道这是否有效,我可以编辑此
通过查看您的 appId
,我在后端没有看到任何东西,所以我不确定问题的真正原因是什么。
您根本不需要设置任何权限——那些仅适用于 OAuth,GetConversationMembersAsync
不需要。您应该只真正需要 manifest.json
中设置的范围,这些范围似乎设置得很好。
但是,对于您的应用程序注册,您可能需要确保在身份验证下选中此项:
如果不是,您可以手动调整您的应用程序注册的清单,设置如下:
"signInAudience": "AzureADandPersonalMicrosoftAccount",
如果 none 有效:
请尝试使用当前的 BotFramework SDK 实现相同功能的 Sample 57, which has a GetMembersAsync
功能。请确保遵循自述文件并按照指定设置所有内容。
让我知道进展如何。如果您需要额外的帮助,您能否尝试尽可能详细地解释您的复制步骤?我想尝试重现这一点,并希望确保我们的步骤匹配——它也可以帮助我找出你可能出错的地方。
实际上,在调用基于操作的消息传递扩展时,有一种方法可以获取两人之间 1:1 私人对话的参与者列表。诀窍是让机器人也进入私人对话。
我一开始也想过这个解决方案,但不知道如何解决,而且没有人建议,我认为不可能一蹴而就。但事实证明我错了。
万一有人遇到这种问题。在这里。
最初我使用 FetchTask 动作消息扩展(基于动作的消息扩展,您不提供预定义的参数列表,而是使用机器人获取参数)。
但它也可以使用带有静态参数的常规操作来完成,所以让我们使用我在问题中使用的方法 OnInvokeActivityAsync
来做一个例子。请参阅下面代码中的注释以获取解释。
protected override async Task<InvokeResponse> OnInvokeActivityAsync(ITurnContext<IInvokeActivity> turnContext, CancellationToken cancellationToken)
{
var connector = turnContext.TurnState.Get<IConnectorClient>();
var conversation = turnContext.Activity.Conversation;
IList<ChannelAccount> members;
try
{
members = await connector.Conversations.GetConversationMembersAsync(conversation.Id, cancellationToken);
}
catch (ErrorResponseException ex)
{
// If the ErrorResponseException contains the response with status code 403, that means our bot is not a member of this conversation.
// In that case, return an adaptive card containing the prompt to add the bot to the current conversation.
// After accepting the prompt, the bot will be added to the conversation and we will be able to obtain the list of conversation participants.
if (ex.Response.StatusCode == HttpStatusCode.Forbidden)
{
return new InvokeResponse
{
Status = 200,
Body = AddBotToConversation()
};
}
throw;
}
// At this point, we have the list of conversation members
var otherMember = members.FirstOrDefault(x => x.Id != turnContext.Activity.From.Id);
return new InvokeResponse
{
Status = 200,
Body = await DoSomethingWithOtherMemberInformationAndReturnACard(otherMember, cancellationToken)
};
}
AddBotToConversation
可以这样定义:
private MessagingExtensionActionResponse AddBotToConversation()
{
var card = new AdaptiveCard(new AdaptiveSchemaVersion(1, 0))
{
Body = new List<AdaptiveElement>()
{
new AdaptiveTextBlock("We need to add the bot to this conversation in order to perform the requested action"),
},
Actions = new List<AdaptiveAction>()
{
new AdaptiveSubmitAction
{
Title = "Continue",
Data = new Dictionary<string, object>
{
// The magic happens here. This tells Teams to add this bot to the current conversation
["msteams"] = new Dictionary<string, bool>
{
["justInTimeInstall"] = true,
}
}
}
}
};
var invokeResponse = new MessagingExtensionActionResponse
{
Task = new TaskModuleContinueResponse
{
Value = new TaskModuleTaskInfo
{
Card = new Attachment
{
ContentType = AdaptiveCard.ContentType,
Content = card
}
}
}
};
return invokeResponse;
}
只需确保消息扩展是基于操作的,而不是基于搜索的。搜索扩展将不支持这种方法。
EDIT 最后但同样重要的是,不要忘记将 "groupchat"
范围添加到 [=16] 下机器人的 "scopes"
集合中=] 集合在 Teams 应用程序 manifest.json 文件中,否则您将无法将您的机器人添加到私人对话中。