Single or array JSON converter.

Often APIs will have actions where one of the parameters can be either a single object or an array of objects, in order to correctly serialize objects to JSON which can be accepted by the API a custom JsonConverter is needed.

This code is borrowed from this stack overflow article.

	
public class SingleOrArrayConverter<T> : JsonConverter
{
	public override bool CanConvert(Type objectType)
	{
		return (objectType == typeof(List<T>));
	}

	public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
	{
		JToken token = JToken.Load(reader);
		if (token.Type == JTokenType.Array)
		{
			return token.ToObject<List<T>>();
		}
		return new List<T> { token.ToObject<T>() };
	}

	public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
	{
		List<T> list = (List<T>)value;
		if (list.Count == 1)
		{
			value = list[0];
		}
		serializer.Serialize(writer, value);
	}

	public override bool CanWrite
	{
		get { return true; }
	}
}
	

For example, where “category” can either be a string or an array of strings.

	
[
  {
    "email": "john.doe@sendgrid.com",
    "timestamp": 1337966815,
    "category": [
      "newuser",
      "transactional"
    ],
    "event": "open"
  },
  {
    "email": "jane.doe@sendgrid.com",
    "timestamp": 1337966815,
    "category": "olduser",
    "event": "open"
  }
]
	

This can be represented by the following class.

	
class Item
{
    [JsonProperty("email")]
    public string Email { get; set; }

    [JsonProperty("timestamp")]
    public int Timestamp { get; set; }

    [JsonProperty("event")]
    public string Event { get; set; }

    [JsonProperty("category")]
    [JsonConverter(typeof(SingleOrArrayConverter<string>))]
    public List<string> Categories { get; set; }
}
	

The category attribute of Item then accepts a list of stype string, if this list only contains 1 item then the attribute is a string and if the list contains more than 1 item then an array of strings is produced.

Categories: Programming

4 Comments

Jens · 18th October 2018 at 12:27 pm

Thanks for sharing (even though it’s borrowed)! Your site came up higher than the stackoverflow post.

xaver · 8th August 2019 at 8:55 am

Thank you very much! I really like this solution

martin · 16th August 2019 at 5:53 pm

Thank you very much! I really like this solution

Single or Array Enum JSON Converter – bitScry · 6th November 2017 at 12:55 pm

[…] addition to the SingleOrArrayConverter mentioned previously I’ve also created a version to translate enums to/from JSON using the name of the enum rather […]

Leave a Reply

Your email address will not be published. Required fields are marked *


Fatal error: Uncaught GuzzleHttp\Exception\ClientException: Client error: `POST https://dc.services.visualstudio.com/v2/track` resulted in a `400 Invalid instrumentation key` response: {"itemsReceived":1,"itemsAccepted":0,"errors":[{"index":0,"statusCode":400,"message":"Invalid instrumentation key"}]} in D:\home\site\wwwroot\wp-content\plugins\application-insights\vendor\guzzlehttp\guzzle\src\Exception\RequestException.php:113 Stack trace: #0 D:\home\site\wwwroot\wp-content\plugins\application-insights\vendor\guzzlehttp\guzzle\src\Middleware.php(66): GuzzleHttp\Exception\RequestException::create(Object(GuzzleHttp\Psr7\Request), Object(GuzzleHttp\Psr7\Response)) #1 D:\home\site\wwwroot\wp-content\plugins\application-insights\vendor\guzzlehttp\promises\src\Promise.php(203): GuzzleHttp\Middleware::GuzzleHttp\{closure}(Object(GuzzleHttp\Psr7\Response)) #2 D:\home\site\wwwroot\wp-content\plugins\application-insights\vendor\guzzlehttp\promises\src\Promise.php(156): GuzzleHttp\Promise\Promise::callHandler(1, Object(GuzzleHttp\P in D:\home\site\wwwroot\wp-content\plugins\application-insights\vendor\guzzlehttp\guzzle\src\Exception\RequestException.php on line 113