Narmanino
Narmanino

Reputation: 33

How to create adaptive cards with situational text values?

I am currently trying to create an adaptive card in a Waterfall Dialog for one of my bots that will display the name and search item (both strings) when rendered. Both of the values I want to use are stored in the Context.Activity.Value property of my dialog, so all I need to know is how to insert those values into my adaptive card at some point during its creation so that the "text" values of the text blocks can contain my values.

I have looked into using empty JSON objects in the adaptive card schema that I could fill somehow during the adaptive card's creation, but have not figured out how to insert said values. I'm a relative beginner with C# and Bot Framework, so I don't know what to try.

Below is the step in my Waterfall Dialog where the adaptive card is made:

private async Task<DialogTurnResult> AdaptiveCardTest(WaterfallStepContext stepContext, 
CancellationToken cancellationToken)
        {
            var introCard = File.ReadAllText("./Content/AdaptiveCardTest.json");

            var card = AdaptiveCard.FromJson(introCard).Card;
            var attachment = new Attachment(AdaptiveCard.ContentType, content: card);

            var response = MessageFactory.Attachment(attachment, ssml: card.Speak, 
            inputHint: InputHints.AcceptingInput);

            await stepContext.Context.SendActivityAsync(response);

            return await stepContext.NextAsync();
        }

AdaptiveCardTest.json is the adaptive card's json file. At the moment it just has an image popup with some text which includes placeholders where I would like the user name and search item to go. The placeholder links are there because the actual links are ridiculously long.

{
    "type": "AdaptiveCard",
    "id": "NewUserGreeting",
    "backgroundImage": "image_url_placeholder"
    "body": [
        {
            "type": "Container",
            "items": [
                {
                    "type": "Image",
                    "url": "image_url_placeholder_2"",
                    "size": "Stretch"
                }
            ]
        },


        {
            "type": "Container",
            "spacing": "None",
            "backgroundImage": "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABYAAAAXCAIAAACAiijJAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAAqSURBVDhPY1RgL2SgDDBBaQrAqBEIMGoEAowagQCjRiDAqBEIQLERDAwAIisAxhgAwtEAAAAASUVORK5CYII=",
            "items": [
                {
                    "type": "TextBlock",
                    "id": "title",
                    "spacing": "Medium",
                    "size": "Large",
                    "weight": "Bolder",
                    "color": "Light",
                    "text": "Hi, I'm **your** Virtual Assistant",
                    "wrap": true
                },
                {
                    "type": "TextBlock",
                    "id": "body",
                    "size": "Medium",
                    "color": "Light",
                    "text": "The user {{Name}} would like to know more about {{SearchItem}}.",
                    "wrap": true
                }
            ]
        }
    ],

}

Any help would be greatly appreciated, thank you!

Upvotes: 3

Views: 5734

Answers (2)

Matt Stannett
Matt Stannett

Reputation: 2728

For your simple scenario I would go with @MikeP's suggestion. In the future if you want to do something more complex where a template won't suffice, then you can build the Adaptive Card dynamically using the .NET SDK once you have installed the AdaptiveCard NuGet package.

The documentation on the .NET SDK is pretty limited but the properties of the AdaptiveCard object usually align with their JSON counterparts.

An example is:

const string ISO8601Format = "yyyy-MM-dd";
string text = "dynamic-text-here;

DateTime today = DateTime.Today;
string todayAsIso = today.ToString(ISO8601Format);

// Create card
AdaptiveCard adaptiveCard = new AdaptiveCard("1.0")
{
    Body =
    {
        new AdaptiveContainer
        {
            Items =
            {
                new AdaptiveTextBlock
                {
                    Text = question,
                    Wrap = true
                },
                new AdaptiveDateInput
                {
                    // This Id matches the property in DialogValueDto so it will automatically be set
                    Id = "UserInput",
                    Value = todayAsIso,
                    Min = today.AddDays(-7).ToString(ISO8601Format),
                    Max = todayAsIso,
                    Placeholder = todayAsIso
                }
            }
        }
    },
    Actions = new List<AdaptiveAction>
    {
        new AdaptiveSubmitAction
        {
            // Data can be an object but this will require the value provided for the 
            // Content property to be serialised it to a string
            // as per this answer https://stackoverflow.com/a/56297792/5209435
            // See the attachment block below for how this is handled
            Data = "your-submit-data",
            Title = "Confirm",
            Type = "Action.Submit"
        }
    }
};

// Create message attachment
Attachment attachment = new Attachment
{
    ContentType = AdaptiveCard.ContentType,
    // Trick to get Adapative Cards to work with prompts as per https://github.com/Microsoft/botbuilder-dotnet/issues/614#issuecomment-443549810
    Content = JsonConvert.DeserializeObject(JsonConvert.SerializeObject(adaptiveCard))
};

cardActivity.Attachments.Add(attachment);

// Send the message
context.SendActivityAsync(cardActivity);

Because Items and Actions are collections, you could have conditional logic inside your code to build up these collections based on some condition at runtime then pass the build collection to Items or Actions which will allow you more flexibility than having a JSON template that you replace placeholder tokens at a known location.

Upvotes: 1

MikeP
MikeP

Reputation: 137

This is something that I have done in the past using Handlebars which is a nice way of replacing tokens in your adaptive card JSON with properties from a model. Just make sure the tokens in your adaptive card JSON match the model properties

Have a look at their site for more detail but it is just a case of doing:

Handlebars.Compile(<Adaptive card template>);

Handlebars is available as a Nuget package you can add into your project.

Upvotes: 0

Related Questions