【问题标题】:How do i get the result of a adaptive card?我如何获得自适应卡的结果?
【发布时间】:2019-02-18 12:29:13
【问题描述】:

我正在尝试获取我的 AdaptiveCard 的结果。 我的机器人使用瀑布对话框。在一个瀑布步骤中,我向用户展示了许多带有时间和日期的房间。然后用户可以选择房间。我尝试了如下所示。可悲的是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);
    }
}

如何让用户选择?

【问题讨论】:

    标签: c# botframework bots adaptive-cards


    【解决方案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"
    }
    

    .. 创建一张如下所示的卡片:

    如果用户在文本框中输入“Testing Testing 123”并点击提交,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 发送的,这意味着提交数据不会作为对话的一部分出现在聊天窗口中,而是保留在自适应卡片上。

    通过 Waterfall Dialogs 使用自适应卡片

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

    在本机上,自适应卡片不像提示那样工作。出现提示时,提示将显示并等待用户输入,然后再继续。但是使用自适应卡片(即使它包含一个输入框和一个提交按钮),自适应卡片中没有任何代码会导致瀑布对话框在继续对话框之前等待用户输入。

    因此,如果您使用的是接受用户输入的自适应卡片,您通常希望处理用户在瀑布对话框上下文之外提交的任何内容。

    话虽如此,如果您想将自适应卡片用作瀑布对话框的一部分,则有一种解决方法。基本上,你:

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

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

    private async Task<DialogTurnResult> DisplayCardAsync(WaterfallStepContext stepContext, CancellationToken cancellationToken)
    {
        // Create the Adaptive Card
        var cardPath = Path.Combine(".", "AdaptiveCard.json");
        var cardJson = File.ReadAllText(cardPath);
        var cardAttachment = new Attachment()
        {
            ContentType = "application/vnd.microsoft.card.adaptive",
            Content = JsonConvert.DeserializeObject(cardJson),
        };
    
        // Create the text prompt
        var opts = new PromptOptions
        {
            Prompt = new Activity
            {
                Attachments = new List<Attachment>() { cardAttachment },
                Type = ActivityTypes.Message,
                Text = "waiting for user input...", // You can comment this out if you don't want to display any text. Still works.
            }
        };
    
        // Display a Text Prompt and wait for input
        return await stepContext.PromptAsync(nameof(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();
    }
    

    在您的主要机器人类 (&lt;your-bot&gt;.cs) 中(第 3 步):

    var activity = turnContext.Activity;
    
    if (string.IsNullOrWhiteSpace(activity.Text) && activity.Value != null)
    {
        activity.Text = JsonConvert.SerializeObject(activity.Value);
    }
    

    【讨论】:

    • 感谢您的回答。它必须是字符串类型吗?我向用户展示了许多不同类型的房间(我的自适应卡使用的是 Input.Choice 而不是 Input.Text)。我已将它们存储在具有标题和值的数组中。标题 将预订的房间和开始时间和结束时间(简称开始和结束时间)显示为字符串。 value 部分以 iso8601 的形式保存 starttime 和 endtime 作为 DateTime 和 roomEmail 作为字符串。值部分被序列化为 json。我想得到用户的选择,所以我得到了开始时间、结束时间和房间电子邮件。
    • 我试过你的教程。问题是当我在 DisplayCardStepAsync 之前写一条消息时。我得到一个 NullReferenceException,因为第三步的 var channelData =…。提示是否必要?难道不能用活动属性替换var postbackactivity吗?这样我就可以跳过 TextPrompt 并且可以将 AfterChoice 方法与活动属性一起使用。
    • @MaxRowe 不一定是文本框输入;您可以使用选择输入。但是,所有输入都将转换为postbackActivity.Value 中的字符串。啊,这可能是因为channelData 在其他一些用户文本上为空。你可以使用if (channelData != null &amp;&amp; channelData.ContainsKey("postback"))。仅当您想在下一个瀑布步骤中使用自适应卡上的用户输入时,才需要提示。自适应卡片不会等待用户输入,因此如果您需要让瀑布等待,则可以在卡片后显示文本提示。
    • 真的,要记住的重要部分是自适应卡片上的所有用户输入都作为postBack(意味着用户不可见)传入&lt;whatever&gt;activity.Value,并且可以在任何方式,你必须从那里抓住它。在OnTurnAsync 方法中最容易抓取。
    • 前一行抛出 NullReferenceException。当我定义channelData。该行试图制作一串空的东西:(。
    猜你喜欢
    • 1970-01-01
    • 2013-11-03
    • 2014-04-30
    • 1970-01-01
    • 2012-07-25
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多