如何在没有 turnContext 的情况下主动触发来自机器人的对话?

How can I proactively trigger a dialog from a bot without a turnContext?

我有一个 Teams 机器人,可以通过 webAPI 向用户发送主动消息。我可以从 Microsoft.Bot.Connector 命名空间获取 ConnectorClient,然后我可以从那里识别相关对话,并调用 SendToConversationAsync 向用户发送消息。

如果我想用它来启动对话,挑战似乎是我没有可供参考的 TurnContext。我发现 post 看起来很有前途,但这仍然取决于对话 运行。理想情况下,我希望能够通过我已经拥有的 ConnectorClient 引用来执行此操作,并且尝试使用 null TurnContext 似乎不起作用。例如,试试这个:

var dialogState = _accessors.ConversationState.CreateProperty<DialogState>(nameof(DialogState));
var dialogSet = new DialogSet(dialogState);
dialogSet.Add(new MyDialog());
DialogContext dc = await dialogSet.CreateContextAsync(turnContext, cancellationToken);
var turnResult = await dc.BeginDialogAsync("MyDialog");

如果 turnContext 为 null,则抛出异常。

这个答案 也有一些有前途的想法,建议伪造传入事件,但我可以做类似 CreateInvokeActivity() 的事情,但将其发送到对话会引发异常。我也不确定如何触发管道以在同一过程中获取消息,而无需像使用 HTTPCLient 那样 POST 原始消息(我相信这需要获取令牌)。该机器人已经与用户进行了 1:1 对话,但如果可能的话,我想让它启动一个对话。有没有办法让 ConnectorClient 主动开始对话,或者以编程方式触发对机器人管道的调用以允许它在那里启动?

您可以使用 ContinueConversationAsync. Please refer to the docs and the sample 从转换参考创建转弯上下文以获取更多信息。

我想出了一个方法来做到这一点,但这可能不是一个理想的方案。我想从 API 开始一个对话框,特别是一个身份验证对话框,它获取用户的 OAuth 令牌以访问图形。如果用户已登录,则立即返回令牌,否则,他们会收到登录提示。我的机器人代码中有这样的内容(为简洁起见进行了编辑):

public static async Task<string> GetTokenAsync(ITurnContext turnContext, CancellationToken cancellationToken)
{
    var dialogState = _accessors.ConversationState.CreateProperty<DialogState>(nameof(DialogState));
    var dialogSet = new DialogSet(dialogState);
    dialogSet.Add(new AuthDialog());
    DialogContext dc = await dialogSet.CreateContextAsync(turnContext, cancellationToken);
    var turnResult = await dc.BeginDialogAsync("AuthDialog");
    await _accessors.ConversationState.SaveChangesAsync(turnContext, false, cancellationToken);

    if(turnResult.Status== DialogTurnStatus.Waiting)
    {
        _log.Debug("Got login request for user-waiting for response");
        return string.Empty;
    }
    else if(turnResult.Result is TokenResponse)
    {
        return ((TokenResponse)turnResult.Result).Token;
    }
    return null;
}

这会创建对话框,如果可能的话,returns 令牌。在我的网站API中,我有这样的东西可以主动调用它:

string conversationID = "CONV_ID_FROM_STATE";

var members = await m_client.Conversations.GetConversationMembersAsync(conversationID);

BotFrameworkAdapter b = new BotFrameworkAdapter(new SimpleCredentialProvider("BOT ID", "BOT_SECRET"));
var message = Activity.CreateMessageActivity();
message.Text = "login";
message.From = new ChannelAccount(members[0].Id);
message.Conversation = new ConversationAccount(id: conversationID, conversationType: "personal", tenantId: :BOT_TENANT_ID);
message.ChannelId = "msteams";

TurnContext t = new TurnContext(b, (Activity)message);
ClaimsIdentity id = new ClaimsIdentity();
id.AddClaim(new Claim("aud", "BOT_ID"));
t.TurnState.Add("BotIdentity", id);
t.TurnState.Add("Microsoft.Bot.Builder.BotAdapter.OAuthScope", "https://api.botframework.com");
t.TurnState.Add("Microsoft.Bot.Connector.IConnectorClient", m_client);
string token = await myBot<AuthDialog>.GetTokenAsync(t, default);

此时,如果令牌是空字符串,则用户尚未登录,否则它应该是用于进行图形调用的有效令牌。我已经用几个新帐户对此进行了测试,它似乎有效,所以我暂时称其为胜利。如果这里有什么根本性的问题,请发表评论。