microsoft / microsoft/AdaptiveCards
[Authoring][.NET][Templating] Inconsistency in accessing $root inside a $when property in adaptive card templating
Nobody has claimed this yet.
- Dominant language
- C#
- Stars
- 2k
- Forks
- 595
- Avg merge
- 1d 19h
- Merged PRs (30d)
- 1
Description
Target Application
Teams, Javascript/web renderer
Problem Description
When using the C# (.NET) adaptivecards template renderer, the $root accessor does not behave as expected inside of $when properties. The following template is a stripped down example for demonstration purposes:
{
"type": "AdaptiveCard",
"body": [
{
"type": "TextBlock",
"size": "medium",
"weight": "bolder",
"text": "${$data} ${$root.UserName}",
"$data": "Hello, ",
"$when": "${$root.UserName != null}"
},
{
"type": "TextBlock",
"text": "Sample text ${jsonStringify($root)} ${$root.UserName}"
}
],
"$schema": "http://adaptivecards.io/schemas/adaptive-card.json",
"version": "1.2"
}
Expected Behavior
When passed a data object with the UserName field filled in:
{
"UserName": "User 123"
}
the card should display "Hello, User 123" in bold lettering and "Sample text {"UserName":"User 123"} User 123" in a line below it.
When passed an empty data object ({}), the card should display only "Sample text {} ${$root.UserName}".
This operates correctly in the JavaScript template renderer as well as in the AdaptiveCard designer.
Actual Behavior
When using the C# template renderer, passing an empty data object behaves correctly, but the first textblock is incorrectly hidden when passed the filled data object.
This is the output of the AdaptiveCards.Templating.AdaptiveCardTemplate object's expand function when passed the filled data:
{
"type": "AdaptiveCard",
"body": [
{
"type": "TextBlock",
"text": "Sample text {\"UserName\":\"User 123\"} User 123"
}
],
"$schema": "http://adaptivecards.io/schemas/adaptive-card.json",
"version": "1.2"
}
You can see that the data items from the $root accessor are properly filled in, but the $when clause is not being handled properly. When we replace the $when property with "${exists($root.UserName)}", the result is no different.
If we simplify the template to not use $data, and therefore not require $root in the $when property (this is feasible here, but not in our production templates where the issue is more apparent), such that our template becomes this:
{
"type": "AdaptiveCard",
"body": [
{
"type": "TextBlock",
"size": "medium",
"weight": "bolder",
"text": "Hello, ${UserName}",
"$when": "${UserName != null}"
},
{
"type": "TextBlock",
"text": "Sample text ${jsonStringify($root)} ${$root.UserName}"
}
],
"$schema": "http://adaptivecards.io/schemas/adaptive-card.json",
"version": "1.2"
}
the template is rendered properly, resulting in the following output form template.expand:
{
"type": "AdaptiveCard",
"body": [
{
"type": "TextBlock",
"size": "medium",
"weight": "bolder",
"text": "Hello, User 123"
},
{
"type": "TextBlock",
"text": "Sample text {\"UserName\":\"User 123\"} User 123"
}
],
"$schema": "http://adaptivecards.io/schemas/adaptive-card.json",
"version": "1.2"
}
This demonstrates that the issue lies with the $root accessor and the $when property together, but neither separately.
Reproduction steps
This is the code I was using to test the template + data against the designer:
var template = new AdaptiveCards.Templating.AdaptiveCardTemplate(@"
{
""type"": ""AdaptiveCard"",
""body"": [
{
""type"": ""TextBlock"",
""size"": ""medium"",
""weight"": ""bolder"",
""text"": ""${$data} ${$root.UserName}"",
""$data"": ""Hello, "",
""$when"": ""${$root.UserName != null}""
},
{
""type"": ""TextBlock"",
""text"": ""Sample text ${jsonStringify($root)} ${$root.UserName}""
}
],
""$schema"": ""http://adaptivecards.io/schemas/adaptive-card.json"",
""version"": ""1.2""
}
");
var cardString = template.Expand(JsonConvert.DeserializeObject(@"
{
""UserName"": ""User 123""
}
"));
Schema Version
1.2
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Start at AdaptiveCards.Templating.AdaptiveCardTemplate and reproduce the expansion with the provided C# template and UserName data. Compare the $root lookup used by the $when expression with the lookup used in text interpolation. Done means the first TextBlock is retained when UserName is present and omitted for an empty data object, matching the documented expected output.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- csharp
- Domain
- backend
- Issue type
- Bug
- Difficulty
- 3/5
- Estimated time
- 1-2 days
- Activity status
- Stale
- Clarity
- Mostly clear
- Newbie friendliness
- 45/100