MarcusEdwards
Crownpeak (Retired)

Working with JSON data

A topic that comes up increasingly is how to create JSON data in your DXM template code. On the face of things, this would seem like a straight forward thing to be able to do -- JSON is just a text-based format (with a specification) after all.

The tricky bit is actually how to handle content data that a content editor has provided in your JSON data, content that may contain all manner of formatting and character data, some of which may cause your JSON text to be malformed or broken if your approach to creating the JSON is naive.

Let's consider the following JSON data that you need to produce for a conference site you're working on:

{
    "Session": {
        "id": 1000,
        "title": "Session Title",
        "type": "keynote",
        "description": "<p><strong>Session Description</strong>Luin le imlad thavron amarth roch yanta avari bereth alph alata sein meleth. Ech ech min thoron mereth ithil. Anto paur or cabed fin iant rochben ross nai glor tavor. Annon nan alda unque anto faroth alph dae iaeth glawar.</p>",
        "date": "2020-01-01",
        "start_time": "09:00",
        "end_time": "09:30",
        "ticketed": false
    }
}

String Building

The naive way to create JSON data is using string concatenation or some other kind of string construction in your template code. Something like this:

var buffer = new StringBuilder(2048); 
buffer.Append(@"{""Session"": { ");
buffer.AppendFormat(
    @"""id"": {0}, ""title"": {1}, ""type"": {2}, ""description"": {3}",
    asset.BranchId,
    asset["session_title"],
    asset["session_type"],
    asset["session_description"]);
...
var json = buffer.ToString();

 

There are a number of problems with this code:

  • it is tedious to write.
  • it is error prone – what if you introduce a new field, or re-organise the field order?
  • there is no protection from inserting "bad" content into a text field – what if the content already as a double quote? This is a classic error of trusting user generated content and leads to problems like SQL injection security faults and so forth.
  • did you notice that the format string already has a bug in it? The placeholders need to be inside double quotes to produce valid JSON.

You may be thinking that you could address some of these problems but escaping all user generated content. That would indeed resolve one of the critical problems, but this still isn't a great solution to the overall problem.

Third-party libraries

Your next idea may be to say that there are some great JSON .NET libraries out there – Newtonsoft JSON.NET is a very popular choice. The problem with this is that you cannot upload and use third-party libraries in template code.

DataContract and Serialization

The answer is to use a data model class using the standard .NET DataContract annotations combined with the Util.SerialiseDataContractJSON method that the Template API exposes for exactly this use case.

Here is a data model class that we can use to serialise the session JSON we're looking at. Note: we have added a static constructor method, FromAsset, that allows us to quick populate the data model from a CMS asset:

using System.Runtime.Serialization;

namespace Project.DataModels
{

  [DataContract()]
  public class Session
  {
    [DataMember(Name = "id")]
    public int Id { get; set; }

    [DataMember(Name = "title")]
    public string Title { get; set; }

    [DataMember(Name = "type")]
    public string Type { get; set; }

    [DataMember(Name = "description")]
    public string Description { get; set; }

    [DataMember(Name = "date")]
    public string Date { get; set; }

    [DataMember(Name = "start_time")]
    public string StartTime { get; set; }

    [DataMember(Name = "end_time")]
    public string EndTime { get; set; }

    [DataMember(Name = "ticketed")]
    public bool IsTicketed { get; set; }

    public static Session FromAsset(Asset asset)
    {
      return new Session {
        Id = asset.BranchId,
        Title = asset.Raw["session_title"],
        Type = asset.Raw["session_type"],
        Description = asset.Raw["session_description"],
        Date = asset.Raw["session_date"],
        StartTime = asset.Raw["session_start_time"],
        EndTime = asset.Raw["session_end_time"],
        IsTicketed = "true".Equals(asset.Raw["session_is_ticketed"])
      };
    }
  }
}

 

And here is what we would need to put in an output template handler to get JSON:

<%@ Import Namespace="Project.DataModels" %>
<% 
var session = Session.FromAsset(asset);
Out.WriteLine(Util.SerializeDataContractJson(session));
%>

 

Once we've created a sample templated asset and added some data, we can get the following output:

{"date":"2020-01-01","description":"<p>Duis consectetur, urna eu venenatis dignissim, felis tortor pharetra orci, id hendrerit neque ipsum sed quam. Proin in pulvinar dolor. Vivamus vitae nulla mauris.</p>","end_time":"09:30","id":235994,"start_time":"09:00","ticketed":false,"title":"Opening Keynote","type":"keynote"}

 

The JSON isn't "pretty" in the sense that it doesn't have newlines or indents to make reading this any easier, but it does make sense that the JSON we produce is as compact as possible for data transfers. If you need to look at the JSON, try one of the many online JSON editors.

There are additional properties that you can set on the DataContract and DataMember annotations to control the order of the elements, whether a property is required or not; whether default values for null or empty properties should be used and a so forth. Refer to the Microsoft .NET documentation for more. 

Conclusion

We've seen a number of approaches to working with JSON data, but the method that provides the most safety is using the DataContract mechanism. It does mean additional work on your part to create the data model classes, which can be a lot of work to get started and to maintain, but the benefit is worth it. In addition, there are tools that can generate much of the code you need from your JSON.

 

Labels (1)

Can't find what you are looking for?

Find Answers

Search our DXM Forum to find answers to questions asked by other DXM users.

Ask a Question

No luck? Ask a question. Our Product and Support teams are monitoring the Forum and typically respond within 48 hours.

Ask a Question