如何获得自适应卡的结果?

时间:2019-02-18 12:29:13

标签: c# botframework bots adaptive-cards

我正在尝试获取AdaptiveCard的结果。 我的机器人使用Waterfalldialogs。在一个Waterfallstep中,我向用户显示了一些带有时间和日期的房间。然后,用户可以选择一个房间。我尝试如下所示。遗憾的是activity保持为空。如何获得自适应卡的结果

private async Task<DialogTurnResult> AfterChoice(WaterfallStepContext step, CancellationToken cancellationToken)
{
    if (step.Result is Activity activity && activity.Value != null && ((dynamic)activity.Value).chosenRoom is JValue chosenRoom)
    {
        dynamic requestedBooking = JsonConvert.DeserializeObject<ExpandoObject>((string)chosenRoom.Value);
        this.roomemail = requestedBooking.roomEmail;
        return await step.EndDialogAsync();
    }
    else
    {
        return await step.BeginDialogAsync(whatever, cancellationToken: cancellationToken);
    }
}

如何获得用户选择?

1 个答案:

答案 0 :(得分:1)

自适应卡发送的“提交”结果与常规用户文本略有不同。当用户键入聊天并发送普通消息时,它最终以Context.Activity.Text结尾。当用户填写自适应卡上的输入时,它会以Context.Activity.Value结尾,该对象是键名是卡中的id,而值是自适应卡中的字段值卡。

例如json:

{
    "type": "AdaptiveCard",
    "body": [
        {
            "type": "TextBlock",
            "text": "Test Adaptive Card"
        },
        {
            "type": "ColumnSet",
            "columns": [
                {
                    "type": "Column",
                    "items": [
                        {
                            "type": "TextBlock",
                            "text": "Text:"
                        }
                    ],
                    "width": 20
                },
                {
                    "type": "Column",
                    "items": [
                        {
                            "type": "Input.Text",
                            "id": "userText",
                            "placeholder": "Enter Some Text"
                        }
                    ],
                    "width": 80
                }
            ]
        }
    ],
    "actions": [
        {
            "type": "Action.Submit",
            "title": "Submit"
        }
    ],
    "$schema": "http://adaptivecards.io/schemas/adaptive-card.json",
    "version": "1.0"
}

..创建一张看起来像这样的卡片:

Test Adaptive Card

如果用户在文本框中输入“ Testing Testing 123”,然后单击Submit,则Context.Activity将类似于:

{ type: 'message',
  value: { userText: 'Testing Testing 123' },
  from: { id: 'xxxxxxxx-05d4-478a-9daa-9b18c79bb66b', name: 'User' },
  locale: '',
  channelData: { postback: true },
  channelId: 'emulator',
  conversation: { id: 'xxxxxxxx-182b-11e9-be61-091ac0e3a4ac|livechat' },
  id: 'xxxxxxxx-182b-11e9-ad8e-63b45e3ebfa7',
  localTimestamp: 2019-01-14T18:39:21.000Z,
  recipient: { id: '1', name: 'Bot', role: 'bot' },
  timestamp: 2019-01-14T18:39:21.773Z,
  serviceUrl: 'http://localhost:58453' }

可以在Context.Activity.Value.userText中看到用户提交的内容。

请注意,自适应卡的提交是作为postBack发送的(在Context.Activity.ChannelData中可见),这意味着提交数据不会在对话的一部分中显示在聊天窗口中,而是保留在自适应卡上

将自适应卡与Waterfall Dialogs 一起使用

您的问题并不完全与此相关,但是由于您可能最终尝试这样做,因此我认为将其包含在答案中可能很重要。

从本质上讲,自适应卡不能像提示一样工作。带有提示,提示将显示并等待用户输入,然后继续。但是对于自适应卡(即使其中包含一个输入框和一个提交按钮),自适应卡中也没有代码,该代码将导致瀑布对话框在继续对话框之前先等待用户输入。

因此,如果您使用的是接受用户输入的自适应卡,则通常要处理用户在“瀑布对话框”上下文之外提交的所有内容。

话虽如此,如果您想在瀑布对话框中使用自适应卡,则有一种解决方法。基本上,您:

  1. 显示自适应卡
  2. 显示文字提示
  3. 将用户的自适应卡输入转换为文本提示输入

在“瀑布对话框”类中(步骤1和2):

    private async Task<DialogTurnResult> DisplayCardAsync(WaterfallStepContext stepContext, CancellationToken cancellationToken)
    {
        var adaptiveCardJson = File.ReadAllText(Path.Combine(".", "AdaptiveCard.json"));
        var cardAttachment = new Attachment()
        {
            ContentType = "application/vnd.microsoft.card.adaptive",
            Content = JsonConvert.DeserializeObject(adaptiveCardJson),
        };
        var cardReply = stepContext.Context.Activity.CreateReply();
        cardReply.Attachments = new List<Attachment>() { cardAttachment };

        // Display the Adaptive Card
        await stepContext.Context.SendActivityAsync(cardReply);

        var opts = new PromptOptions
        {
            Prompt = new Activity
            {
                Type = ActivityTypes.Message,
                Text = "waiting for user input...",
            }
        };

        // Display a Text Prompt and wait for input
        return await stepContext.PromptAsync(TextPrompt, opts);
    }

    private async Task<DialogTurnResult> HandleResponseAsync(WaterfallStepContext stepContext, CancellationToken cancellationToken)
    {
        // Do something with step.result
        // Adaptive Card submissions are objects, so you likely need to JObject.Parse(step.result)
        await stepContext.Context.SendActivityAsync($"INPUT: {stepContext.Result}");
        return await stepContext.NextAsync();
    }

在您的主要机器人课程(<your-bot>.cs)中(步骤3):

    if (activity.Type == ActivityTypes.Message)
    {
        // Ensure that message is a postBack (like a submission from Adaptive Cards
        if (dc.Context.Activity.GetType().GetProperty("ChannelData") != null) {
            var channelData = JObject.Parse(dc.Context.Activity.ChannelData.ToString());
            if (channelData.ContainsKey("postback"))
            {
                var postbackActivity = dc.Context.Activity;
                // Convert the user's Adaptive Card input into the input of a Text Prompt
                // Must be sent as a string
                postbackActivity.Text = postbackActivity.Value.ToString();
                await dc.Context.SendActivityAsync(postbackActivity);
            }
        }            
    }