0
votes

I currently encountered the following problem parsing an adaptive card.

This is the card:

{
    "type": "AdaptiveCard",
    "$schema": "http://adaptivecards.io/schemas/adaptive-card.json",
    "version": "1.4",
    "body": [
        {
            "type": "TextBlock",
            "text": "{{DATE(${$root.AdditionalData['DUE-DATE']},COMPACT)}}",
            "wrap": true
        }
    ]
}

This is the card-content:

{
    "AdditionalData": {
      "DUE-DATE": "2021-09-10T16:29:59Z"
    }
}

Code: c# on .NET Framework 4.7.2 where layout is a string with the above card and content is a string with the above card-content:

 AdaptiveCardTemplate template = new AdaptiveCardTemplate(layout);
 string cardJson = template.Expand(content);

 AdaptiveCardParseResult card = AdaptiveCard.FromJson(cardJson);

And it crashes with:

AdaptiveCards.AdaptiveSerializationException: 'Error reading string. Unexpected token: Undefined. Path 'text', line 1, position 137.'
JsonReaderException: Error reading string. Unexpected token: Undefined. Path 'text', line 1, position 137.

The generated JSON on cardJson looks wrong to me at the text property:

{"type":"AdaptiveCard","$schema":"http://adaptivecards.io/schemas/adaptive-card.json","version":"1.4","body":[{"type":"TextBlock","text":,"wrap":true}]}

I'm using the adaptive cards nuget packages:

  • AdaptiveCards 2.7.2
  • AdaptiveCards.Templating 1.2.

Did I encounter a parsing bug? The value for the text property in cardJson should be "10.9.2021".

In the designer on adaptivecards.io everything works fine for some reason. Does anyone have a fix/workaround?

1
The generated JSON on cardJson is definitely malformed. Upload it to jsonformatter.curiousconcept.com or jsonlint.com and you will get an error that "text": , is missing the property value. So the problem is not in parsing, it is in JSON generation. What are you expecting to get for the value of "text" in cardJson? Is it "{{DATE(2021-09-10T16:29:59Z, COMPACT)}}"? - dbc
@dbc The value should be 10.9.2021. Normally adaptive cards render it in the given context. It works with the adaptivecards designer online (adaptivecards.io), but not with .Net - PlantyPy

1 Answers

0
votes

Use "${formatDateTime(AdditionalData['DUE-DATE'], 'd.M.yyyy')}" to generate the required value 10.9.2021 for your TextBlock:

{
  "type": "AdaptiveCard",
  "$schema": "http://adaptivecards.io/schemas/adaptive-card.json",
  "version": "1.4",
  "body": [
    {
      "type": "TextBlock",
      "text": "${formatDateTime(AdditionalData['DUE-DATE'], 'd.M.yyyy')}",
      "wrap": true
    }
  ]
}

This results in cardJson as required:

{
   "type":"AdaptiveCard",
   "$schema":"http://adaptivecards.io/schemas/adaptive-card.json",
   "version":"1.4",
   "body":[
      {
         "type":"TextBlock",
         "text":"10.9.2021",
         "wrap":true
      }
   ]
}

Demo fiddle #1 here.

Notes:

  • From the documentation page Adaptive Card Templating SDKs: Troubleshooting:

    Q. Why date/time in RFC 3389 format e.g "2017-02-14T06:08:00Z" when used with template doesn't works with TIME/DATE functions?
    A. .NET sdk nuget version 1.0.0-rc.0 exhibits this behavior. this behavior is corrected in the subsequent releases... Please use formatDateTime() function to format the date/time string to RFC 3389 as seen in this example, or you can bypass TIME/DATE functions, and just use formatDateTime(). For more information on formatDateTime(), please go here.

    While this recommendation to use formatDateTime was to fix a problem in 1.0.0-rc.0, the method works in your case as well.

  • According to the Microsoft documentation:

    • Use Dot-notation to access sub-objects of an object hierarchy. E.g., ${myParent.myChild}
    • Use Indexer syntax to retrieve properties by key or items in an array. E.g., ${myArray[0]}

    But, when accessing an object property with a hyphen (or some other reserved operator) in its name, it is apparently necessary to use the Indexer syntax ['DUE-DATE'] to retrieve its value, with the name contained in a single-quoted string, rather than Dot-notation.

  • According to the docs

    There are a few reserved keywords to access various binding scopes. ...

    "$root": "The root data object. Useful when iterating to escape to parent object",
    

    Thus you do not need to use $root when accessing properties of the currently scoped object (which is, by default, the root) when using Dot-notation. If for whatever reason you need or want to address the root object directly, you may use $root.AdditionalData['DUE-DATE'] like so:

    "text": "${formatDateTime($root.AdditionalData['DUE-DATE'], 'd.M.yyyy')}",
    

    Demo fiddle #2 here.