Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Use Adaptive Cards Designer, then replace sample values with real ones in C#

The goal

I want to create (and then edit) Adaptive Cards designs with the Adaptive Cards Designer and use them in my bot.

The steps

1) I created my Adaptive card in the Designer, with sample values, and copied its JSON representation. For example:

{
  "type": "AdaptiveCard",
  "body": [
    {
      "type": "FactSet",
      "id": "myFactSet",
      "facts": [
        {
          "title": "Name:",
          "value": "John Doe"
        }
      ]
    }
  ],
  "$schema": "http://adaptivecards.io/schemas/adaptive-card.json",
  "version": "1.0"
 }

2) Now I want to use this card's design in my C# Bot Framework bot. I put this JSON into my project, where AdaptiveCards v1.1.0 nuget package is included.

3) I parse the card JSON into AdaptiveCards library classes with this line of code:

var card = AdaptiveCard.FromJson(card).Card;

4) Before sending the card to the user I have to fill it with real values, replacing the sample data.

The questions

  1. How do I replace "John Doe" with a real user name? What is the simplest approach? (I already wrote an extension method to get an AdaptiveElement by its id, so I can easily change its values. But tell me please if there is a simpler approach)

  2. And how do I clone an existing AdaptiveElement and put other values into it? For example, if I want to add another FactSet to the card by copying existing myFactSet with all the same style? AdaptiveElement has no Clone() method.

Why other solutions don't fit

Write it in C#

I want to be able to easily edit the card's design with the Designer, but if I rewrite the whole card in C# code, I'll have to do make a change to it every time the card's design changes, and I won't see the result in the Designer.

Do it in javascript

I understand it's easily done with javascript, but I use C# in my bot.

Parse JSON and work with it

I also understand that I can parse the card into JsonObject and deal directly with JsonObjects, clone them, change their properties, but

  1. they are not typed, so there's no IntelliSense support and I can make a typo

  2. I still have to walk all the elements to find the one with the given id (by the way, is there an extension method to easily do this?)

  3. Using JsonObject will not eliminate the need of AdaptiveCards library and the need to call AdaptiveCard.FromJson(card) method (because setting Attachment.Content to a JsonObject doesn't work for some reason).

like image 694
Artemious Avatar asked Dec 14 '18 16:12

Artemious


1 Answers

Remember that JSON is just a string, and I think both of your problems can be solved with string manipulation.

  1. How do I replace "John Doe" with a real user name? What is the simplest approach?

You can replace "John Doe" in the JSON before you convert it into a C# object:

json = json.Replace("John Doe", userName);
var card = AdaptiveCard.FromJson(json).Card;
  1. And how do I clone an existing AdaptiveElement and put other values into it?

The question of deep copying in C# is much discussed. With some ingenuity, you can make a deep copy of any object and Adaptive Card elements are no different. You can use a technique that copies any object or you can make a function that's tailored specifically to Adaptive Cards. Since Adaptive Cards are all about JSON, consider converting the element to JSON and then back again:

var factSet = card.Body.First() as AdaptiveFactSet;
factSet = JsonConvert.DeserializeObject<AdaptiveFactSet>(JsonConvert.SerializeObject(factSet));
factSet.Facts.First().Value = userName;
card.Body.Add(factSet);

However, you may not even need to worry about deep-copying since you're starting out with JSON. Maybe you can just take the JSON for a specific element from the designer and then deserialize it multiple times:

factSet1 = JsonConvert.DeserializeObject<AdaptiveFactSet>(factSetJson);
factSet2 = JsonConvert.DeserializeObject<AdaptiveFactSet>(factSetJson);

I want to be able to easily edit the card's design with the Designer, but if I rewrite the whole card in C# code, I'll have to do make a change to it every time the card's design changes, and I won't see the result in the Designer.

If you have your card represented in both C# and JSON, then it shouldn't be too difficult to make a small change in the designer to see how it looks and then modify your C# accordingly. If you think it would be really cool to have a tool that can take a card's JSON and automatically write the C# that could generate it, then I agree :)

like image 100
Kyle Delaney Avatar answered Nov 14 '22 22:11

Kyle Delaney