在BotFramework中向用户发送来自机器人的消息

14

我有一个基于BotFramework 3.5构建的机器人,并托管在Azure上作为WebApp。我在实现机器人需要响应用户输入的情况时没有遇到任何问题。然而,现在需要通过一些时间表来教机器人开始对话。 为了达成这个目标,我创建了一个WebJob,它基本上是一个简单的控制台应用程序。下面是用于从机器人向用户发起消息的代码:

            var botAccount = new ChannelAccount(id: from);
            var userAccount = new ChannelAccount(id: to);
            var conversation = new ConversationAccount(false, conversationId);

            var connector = new ConnectorClient(serviceUrl);

            IMessageActivity message = Activity.CreateMessageActivity();
            message.From = botAccount;
            message.Recipient = userAccount;
            message.Conversation = conversation;
            message.Text = text;
            message.Locale = locale;
            await connector.Conversations.SendToConversationAsync((Activity)message);

from, to, serviceUrl, conversationId - 从之前的对话中获取,所以我期望它们是有效的。然而在 SendToConversationAsync 方法中抛出了异常:

System.UnauthorizedAccessException: Authorization for Microsoft App ID 3a26a4d4-f75a-4feb-b3e0-37a7fa24e5fc failed with status code Unauthorized and reason phrase 'Unauthorized' ---> System.Net.Http.HttpRequestException: Response status code does not indicate success: 401 (Unauthorized)

app.config文件包含与原始机器人API相同的值,包括AppId和AppSecret。我看到了一些关于同一主题的问题,但没有找到答案。

我是否遗漏了什么?从控制台应用程序代表机器人发送消息是有效的方法吗?


你的 Web 应用程序是否使用身份验证和授权? - Thomas
它使用在 web.config 中定义的 3 个身份验证参数(AppId、AppPassword 和 BotId)。相同的值被注入到控制台应用程序中。 - Artem
你能发布一下配置了身份验证的Web应用程序的代码吗?你是如何进行Web应用程序身份验证的?你发送了一个令牌吗? - Thomas
2个回答

24
根据您的描述,我按照此tutorial入门连接器,并按照此tutorial发送和接收活动。
根据您的代码,我创建了控制台应用程序并复现了同样的问题,然后我发现了一个关于类似问题的git issue。经过一些尝试,我在我的端上成功地使其正常工作,您可以参考它:
MicrosoftAppCredentials.TrustServiceUrl("{ServiceUrl}", DateTime.Now.AddDays(7));
var account=new MicrosoftAppCredentials("MicrosoftAppIdKey", "MicrosoftAppPasswordKey");
var connector = new ConnectorClient(new Uri("{ServiceUrl}"),account);

或者

实现您的DelegatingHandler

public class MyDelegatingHandler : DelegatingHandler
{
    private string _token;
    public MyDelegatingHandler(string token)
    {
        _token = token;
    }

    protected override Task<HttpResponseMessage> SendAsync(
    HttpRequestMessage request, CancellationToken cancellationToken)
    {
        request.Headers.Authorization = new System.Net.Http.Headers.AuthenticationHeaderValue("Bearer", _token);
        return base.SendAsync(request, cancellationToken);
    }
}

然后,您需要按照以下方式构建您的ConnectorClient
var account=new MicrosoftAppCredentials("{MicrosoftAppIdKey}", "{MicrosoftAppPasswordKey}");
var jwtToken=await account.GetTokenAsync();
var connector = new ConnectorClient(new Uri("{serviceUrl}"),handlers:new MyDelegatingHandler(jwtToken));

这是我的控制台应用程序代码片段,您可以参考它:

try
{
    var userAccount = new ChannelAccount() { Id = "default-user", Name = "user" };
    var botAccount = new ChannelAccount() { Id = "934493jn5f6f348f", Name = "console-Bot" };
    string url = "{serviceUrl}";

    MicrosoftAppCredentials.TrustServiceUrl(url, DateTime.Now.AddDays(7));
    var account = new MicrosoftAppCredentials("{MicrosoftAppIdKey}", "{MicrosoftAppPasswordKey}");
    var connector = new ConnectorClient(new Uri(url), account);

    IMessageActivity message = Activity.CreateMessageActivity();
    message.From = botAccount;
    message.Recipient = userAccount;
    message.Conversation = new ConversationAccount() { Id = "{conversationId}" };
    message.Text = "Message sent from console application!!!";
    message.Locale = "en-us";
    var response = await connector.Conversations.SendToConversationAsync((Activity)message);
    Console.WriteLine($"response:{response.Id}");
}
catch (Exception e)
{
    Console.WriteLine($"exception:{e.Message}\r\n{e.StackTrace}");
}

结果

enter image description here


你的帖子帮助我解决了发送主动消息时的身份验证问题,非常感谢。然而,我发现可以将你上面发布的两行JWT访问令牌代码注释掉,重新启动我的测试服务器应用程序,仍然成功进行身份验证并发送主动消息。 - camelCase
3
无法给这个点赞次数足够多! - chris31389
太棒了!!这个非常有效..但是我在想,如果另一个机器人而不是控制台应用程序尝试向用户发送消息,是否会起作用?(使用其自己的MicrosoftAppIdKey和secret)? - Mohan Kumar DB
优秀的回答! - The Memebot
调用 MicrosoftAppCredentials.TrustServiceUrl 会开始新的7天过期时间还是继续使用现有的?谢谢。 - Richard Bailey

0

尝试像这样创建一个新的对话:

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

当然我试过了,但是不起作用。显然错误与对话创建方式无关。 - Artem

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接