Deserializing JSON that contains an embedded JSON string

When you send mail, you put a letter in an envelope and put routing information on the envelope. The postal service uses the routing information to deliver the envelope to a specific mailbox. The mailbox owner then opens the envelope and reads the letter.

Sometimes you may need to deal with the JSON equivalent of this scenario. You may have a JSON message that has routing information and contains an embedded JSON string.

One use of this is when you’re using a plugin architecture. The service that has the plugins loaded may receive JSON messages and relay the embedded JSON to the appropriate plugin for further processing.

In this article, I’ll show an example of code that handles deserializing JSON that contains an embedded JSON string.

Generating the JSON envelope

The following is an example of a JSON envelope:

{ "To": "PaymentProcessor", "Payload": "{\"Id\":\"1\",\"Amount\":20.21}" }
Code language: JSON / JSON with Comments (json)

It contains routing information and an embedded JSON string. The only thing special about the embedded JSON is that it’s been escaped / encoded.

This JSON was generated by serializing the following class:

public class JsonEnvelope { public string To { get; set; } public string Payload { get; set; } }
Code language: C# (cs)

The sender would generate this JSON envelope by first serializing the payload, then the envelope, like this:

var jsonEnvelope = new JsonEnvelope() { To = "PaymentProcessor", Payload = JsonSerializer.Serialize(new Payment() { Id = "1", Amount = 20.21m }) }; var jsonToSend = JsonSerializer.Serialize(jsonEnvelope, options);
Code language: C# (cs)

Routing the JSON envelope

The sender sends the JSON envelope to a service. The service contains a route map that provides information about how to route messages. You can populate the route map in many ways (that’s out of scope of this article though).

The service has to deserialize the JSON envelope to get the routing information. Once it has the routing information, it can route the embedded JSON string to the appropriate processor:

public static void Route(string json) { var jsonEnvelope = JsonSerializer.Deserialize<JsonEnvelope>(json); var processor = routeMap[jsonEnvelope.To]; processor.Process(jsonEnvelope.Payload); } private static readonly Dictionary<string, IMessageProcessor> routeMap = new Dictionary<string, IMessageProcessor>();
Code language: C# (cs)

Note: In this example, it’s using DLL plugins. Inside the plugins, they would implement the IMessageProcessor interface (shown below) and the service would have the processor objects loaded into this map. This is just one way of doing it. They key point is that the service has information that allows it to relay the JSON message to the appropriate processor.

public interface IMessageProcessor { void Process(string json); }
Code language: C# (cs)

Processing the embedded JSON string

The embedded JSON string is passed into the processor. The JSON can then be deserialized into the appropriate type and processed. In this example, the JSON is being passed into a PaymentProcessor class, which deserializes the JSON into a Payment object.

public class PaymentProcessor : IMessageProcessor { public void Process(string paymentJson) { var payment = JsonSerializer.Deserialize<Payment>(paymentJson); Console.WriteLine($"Processing payment {payment.Id}"); } } public class Payment { public string Id { get; set; } public decimal Amount { get; set; } }
Code language: C# (cs)

Leave a Comment