microsoft / microsoft/AdaptiveCards

[Authoring][.NET][Templating] Inconsistency in accessing $root inside a $when property in adaptive card templating

Open
#6,026 0 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

Area-Inconsistency Area-Templating Bug
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

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. 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

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.