Handling Flexible JSON Formats in C#: A Case Study with JSON Converters

Shahar Shokrani
3 min readJul 21, 2024

--

Introduction

When dealing with JSON data in .NET applications, you might encounter scenarios where a single property can have different formats. A common example is when a JSON property can either be a single string or an array of strings. This can pose a challenge when trying to deserialize such JSON data into a strongly typed object. In this article, we’ll explore how to tackle this problem using a custom JSON converter in C#.

The Problem

Imagine you have a JSON structure where a property can either be a single string or an array of strings. For example, consider the following JSON:

{
"name": "Example Object",
"description": "This is a description."
}

And another variant:

{
"name": "Example Object",
"description": ["This is a description.", "Another description."]
}

The challenge is to handle both formats seamlessly during deserialization.

The Solution

To solve this problem, we can create a custom JSON converter in C#. This converter will handle the property, allowing it to parse either a single string or an array of strings and store them as a comma-separated string.

Step-by-Step Implementation

First, we’ll create a custom JSON converter named CommaSeparatedStringConverter:

using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using System;
using System.Collections.Generic;

public class CommaSeparatedStringConverter : JsonConverter
{
public override bool CanConvert(Type objectType)
{
return objectType == typeof(string);
}

public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
{
if (reader.TokenType == JsonToken.String)
{
return (string)reader.Value;
}
else if (reader.TokenType == JsonToken.StartArray)
{
List<string> list = new List<string>();
while (reader.Read() && reader.TokenType != JsonToken.EndArray)
{
if (reader.TokenType == JsonToken.String)
{
list.Add((string)reader.Value);
}
else
{
throw new JsonSerializationException("Unexpected token type: " + reader.TokenType.ToString());
}
}
return string.Join(",", list);
}
else
{
throw new JsonSerializationException("Unexpected token type: " + reader.TokenType.ToString());
}
}

public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
{
throw new NotImplementedException();
}
}

Step 2: Define a Class with the Property (Example)

Next, define a class that includes a property using this converter. For this example, let’s create a simple class ExampleObject:

using Newtonsoft.Json;

public class ExampleObject
{
[JsonProperty(PropertyName = "name")]
public string Name { get; set; }

[JsonProperty(PropertyName = "description")]
[JsonConverter(typeof(CommaSeparatedStringConverter))]
public string Description { get; set; }
}

Step 3: Write Unit Tests

Now you can deserialize JSON data into the ExampleObject class seamlessly, regardless of whether Description is a single string or an array of strings. We will use xUnit for writing unit tests to validate our implementation:

using Newtonsoft.Json;
using Xunit;

public class CommaSeparatedStringConverterTests
{
[Fact]
public void DeserializeObject_ExampleObject_ShouldParseCorrectly()
{
// Arrange
string json1 = @"{
'name': 'Example Object 1',
'description': 'This is a description.'
}";

string json2 = @"{
'name': 'Example Object 2',
'description': ['This is a description.', 'Another description.']
}";

// Act
ExampleObject obj1 = JsonConvert.DeserializeObject<ExampleObject>(json1);
ExampleObject obj2 = JsonConvert.DeserializeObject<ExampleObject>(json2);

// Assert
Assert.Equal("Example Object 1", obj1.Name);
Assert.Equal("This is a description.", obj1.Description);
Assert.Equal("Example Object 2", obj2.Name);
Assert.Equal("This is a description.,Another description.", obj2.Description);
}
}

Conclusion

By creating a custom JSON converter, we can handle flexible JSON formats in C# effectively. The CommaSeparatedStringConverter ensures that the property can be parsed correctly, whether it's a single string or an array of strings. This approach can be adapted to other similar scenarios, providing a robust solution for handling varied JSON data structures in .NET applications.

--

--

No responses yet