Adaptive Cards are platform-agnostic snippets of UI, authored in JSON, that apps and services can openly exchange. When delivered to a specific app, the JSON is transformed into native UI that automatically adapts to its surroundings. It helps design and integrate light-weight UI for all major platforms and frameworks.
Adaptive Cards Templating is a revolutionary change. It enables the separation of Data & Layouts.
Let's understand the Adaptive Cards online designer. The designer contains multiple panels that serve different purposes, as shown in the following image.
- Card Elements: List of all elements available for use within Adaptive Cards.
- Rendered Card: Preview rendering of the card as it would appear in the currently selected host app.
- Card Payload Editor: The browser-friendly JSON editor contains the source of the Adaptive Card that's rendered in the Rendered Card pane.
- Card Structure: The card is represented in this panel as a hierarchical structure. Notice that as you select elements in this panel, the corresponding control is highlighted in the Rendered Card pane.
- Element Properties: The properties, including those that aren't specified in the source of the Adaptive Card, are displayed in this panel for the control currently selected in the Card Structure panel.
- Sample Data Editor: This panel contains the JSON used when using the templating capability of Adaptive Cards.
Templating enables the separation of data from the layout in your Adaptive Card. The template language is the syntax used to author a template.
Binding syntax changed from {...} to ${...} i.e. “text": "Hello {name}" becomes "text": "Hello ${name}"
Static Card Payload
{
"type": "TextBlock",
"text": "Manoj Mittal"
}
Template Payload
{
"type": "TextBlock",
"text": "${UserName}"
}
Let's create a bot framework sdkv4 project and associate it with adaptive card templating.
Step 1. Build Bot Framework SDKV4 C# Project
Prerequisites
Azure Bot Framework template installed with Visual Studio 2019.
- Launch Visual Studio 2019
- Select Create new project
- Select Azure Bot Framework (.Net Core 2.1 or 3.1)
- Create Project.
Step 2. Create an Adaptive Card Template
- Login to https://adaptivecards.io/designer/
- The card Element Section designs your card with a placeholder, which will be used to bind the data at the client side.
{
"$schema": "http://adaptivecards.io/schemas/adaptive-card.json",
"type": "AdaptiveCard",
"version": "1.2",
"body": [
{
"id": "cardHeader",
"type": "Container",
"items": [
{
"id": "planetName",
"type": "TextBlock",
"weight": "Bolder",
"size": "Medium",
"text": "${name}"
}
]
},
{
"type": "Container",
"id": "cardBody",
"items": [
{
"id": "planetSummary",
"type": "TextBlock",
"wrap": true,
"text": "${summary}"
},
{
"id": "planetDetails",
"type": "ColumnSet",
"columns": [
{
"type": "Column",
"width": 100,
"items": [
{
"id": "planetImage",
"size": "Stretch",
"type": "Image",
"url": "${imageLink}"
}
]
},
{
"type": "Column",
"width": 250,
"items": [
{
"type": "FactSet",
"facts": [
{
"id": "orderFromSun",
"title": "Order from the sun:",
"value": "${id}"
},
{
"id": "planetNumSatellites",
"title": "Known satellites:",
"value": "${numSatellites}"
},
{
"id": "solarOrbitYears",
"title": "Solar orbit (*Earth years*):",
"value": "${solarOrbitYears}"
},
{
"id": "solarOrbitAvgDistanceKm",
"title": "Average distance from the sun (*km*):",
"value": "${solarOrbitAvgDistanceKm}"
}
]
}
]
}
]
},
{
"id": "imageAttribution",
"type": "TextBlock",
"size": "Small",
"isSubtle": true,
"wrap": true,
"text": "${imageAlt}",
"weight": "Lighter"
}
]
}
],
"actions": [
{
"type": "Action.OpenUrl",
"title": "Learn more on Wikipedia",
"url": "${wikiLink}"
}
]
}
The card will look like this.
Create a Folder into Visual Code Project name Resource.
Add Json Template with the name of card.json.
Step 3. Add Card and Data Binding
Browse Project and Add Nuget Package
AdaptiveCards.Templating
Browse echobot.cs file
Load the card.json into
private readonly string _cards = Path.Combine(".", "Resources", "Card.json");
On the Message Activity Function, Load Json into the template variable.
var adaptiveCardJson = (File.ReadAllText(_cards));
AdaptiveCardTemplate template = new AdaptiveCardTemplate(adaptiveCardJson);
Step 4. Add Data and bind with template variable
Add a reference to AdaptiveCards.Templating.
Note. I used static data or hard-coded data here for article purposes. Data JSON can be rendered via API also.
var adaptiveCardJson = (File.ReadAllText(_cards));
AdaptiveCardTemplate template = new AdaptiveCardTemplate(adaptiveCardJson);
var myData = new
{
id = "1",
name = "Saturn",
summary = "Saturn is the sixth planet from the Sun and the second-largest in the Solar System, after Jupiter. It is a gas giant with an average radius about nine times that of Earth. It has only one-eighth the average density of Earth; however, with its larger volume, Saturn is over 95 times more massive. Saturn is named after the Roman god of wealth and agriculture; its astronomical symbol (♄) represents the god's sickle.",
solarOrbitYears = "29.46",
solarOrbitAvgDistanceKm = "1433525000",
numSatellites = "82",
wikiLink = "https://en.wikipedia.org/wiki/Saturn",
imageLink = "https://upload.wikimedia.org/wikipedia/commons/c/c7/Saturn_during_Equinox.jpg",
imageAlt = "NASA / JPL / Space Science Institute [Public domain]"
};
string cardJson = template.Expand(myData);
var cardAttachment = CreateAdaptiveCardAttachment(cardJson);
Now turn to render the adaptive card.
private static Attachment CreateAdaptiveCardAttachment(string _card)
{
var adaptiveCardAttachment = new Attachment()
{
ContentType = "application/vnd.microsoft.card.adaptive",
Content = JsonConvert.DeserializeObject(_card),
};
return adaptiveCardAttachment;
}
Step 5. Run Code locally (F5) using Bot Framework Emulator
Data and Layout are separated while rendering the card. Layouts exist at the client side and binding of data also happens on the client side. As data will come from the API, it will have server-side execution.
Earlier we used to bind the Data and Layout on the server side and traverse the entire structure.
Code Base can be downloaded from here.
I hope you have enjoyed and learned something new in this article. Thanks for reading and stay tuned for the next article.