【问题标题】:Proactively sending message through bot using a web app使用 Web 应用程序通过机器人主动发送消息
【发布时间】:2019-04-11 08:39:24
【问题描述】:

已解决

感谢用户 MarkMoose,我意识到我的数据库表没有存储完整的 ID。 未来的调试器:如果这不能帮助您解决问题,请查看我与 MarkMoose 的对话,他们指导我完成了非常有用的故障排除步骤。

我正在尝试使用 Microsoft Bot SDK 4.0 版创建托管在 Azure 上的 Microsoft Teams 机器人。

流程如下

  1. Web 应用程序警报触发器。向机器人发送一个 POST 请求,其中包含(从用户之前的消息中收集的所有这些数据)

    • 致 ID(收件人用户)
    • 收件人姓名(收件人用户)
    • 来自 ID(我的机器人)
    • 发件人姓名(我的机器人)
    • 频道 ID
    • 对话 ID
    • 服务 URL(收件人用户)
  2. Bot 从 JSON 中提取该信息形成新的消息活动

  3. Bot 向用户发送活动

问题:当机器人尝试使用上面列出的凭据创建ConversationAccount 对象时,它会引发以下错误:

捕获的异常:Microsoft.Bot.Schema.ErrorResponseException:操作返回了无效的状态代码“BadRequest”

这里是相关部分的代码。

请特别注意以下几行:

var account = new MicrosoftAppCredentials(botCreds["App ID"], botCreds["App Password"]);
var jwtToken = await account.GetTokenAsync();
ConnectorClient connector = new ConnectorClient(new System.Uri(serviceURL), account);

当我找到其他人解决我的问题时,这些行略有不同。在我当前版本的代码中,我使用的是this posts solution。我也尝试过他创建的 DelegatingHandler 类,但它抛出了同样的错误。

/// <summary>
/// Sends a message to a user or group chat.
/// </summary>
/// <param name="forwardContext">JSON object containing credentials for destination chat.</param>
/// <param name="messageToSend">The message to forward.</param>
/// <returns></returns>
private async Task ForwardMessage(JToken forwardContext, string messageToSend)
{
    // Collect data from JSON input
    var restCmd = forwardContext;
    var toId = (string) restCmd["toId"];
    var toName = (string) restCmd["toName"];
    var fromId = (string) restCmd["fromId"];
    var fromName = (string) restCmd["fromName"];
    var channelId = (string) restCmd["channel"];
    var serviceURL = (string) restCmd["serviceURL"];
    var conversationId = (string) restCmd["conversation"];
    var cred_str = $@"toId: {toId}
    toName: {toName}
    fromId: {fromId}
    fromName: {fromName}
    channelId: {channelId}
    serviceURL: {serviceURL}
    conversationId: {conversationId}";
    _logger.LogInformation(cred_str);
    _logger.LogInformation($"Forwarding the following message to {toName}: {messageToSend}");

    Dictionary<string, string> botCreds = GetBotCredentials();

    // Create relevant accounts
    ChannelAccount userAccount = new ChannelAccount(name: toName, id: toId);
    ChannelAccount botAccount = new ChannelAccount(name: fromName, id: fromId);
    if (!MicrosoftAppCredentials.IsTrustedServiceUrl(serviceURL))
    {
        _logger.LogInformation($"Adding to trusted service urls: {serviceURL}");

        // Register the service URL as trusted
        MicrosoftAppCredentials.TrustServiceUrl(serviceURL);
    }
    MicrosoftAppCredentials.TrustServiceUrl(serviceURL);
    var account = new MicrosoftAppCredentials(botCreds["App ID"], botCreds["App Password"]);
    var jwtToken = await account.GetTokenAsync();
    ConnectorClient connector = new ConnectorClient(new System.Uri(serviceURL), account);

    // Create a new message activity
    IMessageActivity message = Activity.CreateMessageActivity();

    conversationId = (
        await connector
        .Conversations
        .CreateDirectConversationAsync(botAccount, userAccount)).Id;

    // Set relevant message details
    message.From = botAccount;
    message.Recipient = userAccount;
    message.Text = messageToSend;
    message.Locale = "en-Us";
    message.ChannelId = channelId;

    // Create a new converstaion and add it to the message.
    message.Conversation = new ConversationAccount(id: conversationId);
    await connector.Conversations.SendToConversationAsync((Activity) message);
}

这是我收集上述信息的代码。当用户第一次与机器人交互时调用此函数。

/// <summary>
    /// Called only when the !setup command is sent to the bot.
    /// Updates the chats info in the DB.
    /// </summary>
    /// <param name="activity">Activity of the message the "!setup" command was sent in.</param>
    /// <returns>True if the update query executed fine.</returns>
    private bool SetupCommand(Activity activity)
    {
        // Connect to the database
        this.database = new DBConnection(serverIP, databaseName, userName, password, _logger);
        this.database.Connect();
        var tableName = "ms_teams_chats";

        // Data gathered from Activity for database.

        // User ID
        string toId = activity.From.Id;

        // User Name
        string toName = activity.From.Name;

        // Bot ID
        string fromId = activity.Recipient.Id;

        // Bot Name
        string fromName = activity.Recipient.Name;

        // Users service URL
        string serviceURL = activity.ServiceUrl;

        // The platform the message came from. Example: 'skype'
        string channelId = activity.ChannelId;
        string conversationID = activity.Conversation.Id;

        string conversationName = activity.Conversation.Name;
        bool isGroupChat = activity.Conversation.IsGroup ?? false;

        string upsertQuery = string.Empty;
        upsertQuery = $@"
            INSERT INTO {tableName} 
                (user_id, user_name, assoc_bot_id, assoc_bot_name, service_url, channel_id, conversation_id, is_group_chat)
            VALUES (
                '{toId}', '{toName}', '{fromId}', '{fromName}', '{serviceURL}', '{channelId}', '{conversationID}', {isGroupChat}
            )
            ON DUPLICATE KEY UPDATE
            user_id = '{toId}',
            user_name = '{toName}',
            assoc_bot_id = '{fromId}',
            assoc_bot_name = '{fromName}',
            service_url = '{serviceURL}',
            channel_id = '{channelId}',
            conversation_id = '{conversationID}',
            is_group_chat = {isGroupChat}
        ";
        try
        {
            this.database.ExecuteNonQuery(upsertQuery);
        }
        catch (System.Exception e)
        {
            _logger.LogError($"Could not update users information. \nError:{e.ToString()}");
            return false;
        }

        return true;
    }

【问题讨论】:

  • 你试过设置message.ChannelId吗?在the doc 他们有它。
  • 是的,很抱歉,似乎在格式化时我必须删除该行。它在那里,我更新了帖子。我得到了同样的错误。
  • 你能试试this sample code吗?

标签: c# botframework microsoft-teams


【解决方案1】:

您似乎正在为我上周遇到的同样问题而苦苦挣扎。似乎 CreateDirectConversationAsync 在 MS Teams 中不起作用,因为 Teams 还需要一个tennantId。 我在这里找到了一个声明:https://github.com/Microsoft/BotBuilder/issues/2944

答案提到了 SDK V4 中不再提供的 nuget 包 (Microsoft.Bot.Connector.Teams)。但正如我所见,您已经从 JSON 输入中获得了一个 conversationId,这应该不是问题。只需使用您在 JSON 中传递的 conversationId。 如果你这样做,你的代码可能看起来像:

private static async Task SendProActiveMessgae()private async Task ForwardMessage(JToken forwardContext, string messageToSend)
{
    // Collect data from JSON input
    var restCmd = forwardContext;
    var toId = (string) restCmd["toId"];
    var toName = (string) restCmd["toName"];
    var fromId = (string) restCmd["fromId"];
    var fromName = (string) restCmd["fromName"];
    var serviceURL = (string) restCmd["serviceURL"]
    var conversationId = (string) restCmd["conversation"];

    var uri = new Uri(serviceURL);
    var appId = "APP ID";
    var appSecret = "APP PASSWORD";
    ConnectorClient connector = new ConnectorClient(uri, appId, appSecret);

    var activity = new Activity()
    {
        Type = ActivityTypes.Message,
        From = new ChannelAccount(fromId, fromName),
        Recipient = new ChannelAccount(toId, toName),
        Conversation = new ConversationAccount(false, "personal", conversationId),
        Text = messageToSend
    };
    try
    {
        MicrosoftAppCredentials.TrustServiceUrl(serviceURL);
        await connector.Conversations.SendToConversationAsync(conversationId, activity);
    }
    catch (Exception ex)
    {
        Console.WriteLine(ex.Message);
    }
}

【讨论】:

  • 不幸的是,我仍然收到Forbidden 错误。我对此很陌生,所以我不确定如何调试它。还有其他想法吗?感谢您的帮助。
  • 我不知道 Teams 需要有关团队/群聊的不同信息。你知道我在哪里可以找到更多关于我需要什么的信息吗?您提到了租户 ID,我也应该收集它吗?我还没有找到使用它的文档。
  • hmm... Forbidden 错误可能是由很多事情引起的。所以首先要做的事情:你假设你将机器人部署到天蓝色(因为你已经有一个应用程序 ID 和秘密)并且你的 json 中的数据直接来自你的机器人的对话引用对象?它是对 Teams 中一对一聊天的引用吗?你能告诉我你得到的 serviceUrl 吗?我还没有使用租户 ID。但我在这里找到了一些额外的阅读材料link
  • 如果似乎没有任何效果。也许尝试使用像邮递员这样的程序直接与你的机器人的 REST api 对话。 (Microsoft.Bot.Connector 命名空间只为这个 C# 的 REST api 提供了一个包装器)关于 REST api 的更多信息可以找到here
  • 不客气!根据文档,群聊仅限于开发者预览版,但很快就会发布到 Teams 的生产版本。但是您可以使用频道对话(也称为团队聊天)向多个用户发送消息我还没有研究过这个功能,但我会开始阅读here
猜你喜欢
  • 2021-09-10
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-07-25
  • 2021-08-30
  • 2016-05-03
相关资源
最近更新 更多