Custom JSON Serialization for Each Item in Ienumerable

Json.Net serialization of IEnumerable with TypeNameHandling=auto

The default automatic behaviour of Json.Net, when deserializing into an IEnumerable or IList field, is to create a List instance. If you assign an Array instance, then the only way to restore your object to it original instance state is for Json.Net to add the $type meta data, which is what you are seeing. i.e. there are many ways to deserialize into an IEnumerable field.

By using a List<string> instance:

var myEvent = new MyClass
{
Values = new List<string>(),
};

with:

public class MyClass
{
public IEnumerable<string> Values { get; set; }
}

results in (when serialized):

{"Values":["hello"]}

Also, if you use an explicit constructable type or use the default List, then Json.Net will use that and omit $type;

For instance:

string[] Values { get; set; } = new string[0]; // not needed
IEnumerable<string> Values { get; set; } = new string[0]; //$type needed
IEnumerable<string> Values { get; set; } = new Stack<string>(); //$type needed
IEnumerable<string> Values { get; set; } = new List<string>; // not needed
List<string> Values { get; set; } = new List<string>; // not needed

ObservableCollection<string> Values { get; set; } =
new ObservableCollection<string>(); // not needed

How to serialize an IEnumerable like a regular class?

Attach the JsonObjectAttribute to your Computer type:

[JsonObject]
class Computer : IEnumerable

This will force serialization to serialize it like an object and not a collection, thus ignoring IEnumerable or IEnumerable<T> altogether.

Note that this will completely ignore the IEnumerable part so whatever would be serialized through that collection support will either have to be ignored, or handled through those properties as you showed.


As comments on your question have already stated, it seems like a strange design to make a computer an implicit collection of its components. Since you've stated it is legacy code you're hoping not to disturb too much, and only want to fix the Json.net serialization, you can use that attribute to circumvent the automatic collection serialization.

Json DeSerialization of an array to IEnumerable failing

CustomerExtensions implements IEnumerable<CustomerExtension>, so the deserializer by default will be expecting it to serialize and deserialize from a json array. It will try to create a new instance, then call Add(CustomerExtension item) to populate it. However, you don't implement IList, so there is no Add() method that it can use, and it doesn't know what to do.

Why do you need a custom class for this? There is no additional logic in your class, wouldn't it be enough to have public List<CustomerExtension> CustomerExtensions { get; set; }?

Edit

Since you aren't able to change the class definition, you can create a custom JsonConverter instead:

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

public class CustomerExtensionsConverter : JsonConverter<CustomerExtensions>
{
public override bool CanWrite => false;

public override CustomerExtensions ReadJson(JsonReader reader, Type objectType, CustomerExtensions existingValue, bool hasExistingValue, JsonSerializer serializer)
{
var list = serializer.Deserialize<List<CustomerExtension>>(reader);
return new CustomerExtensions(list);
}

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

To use the converter, add it to the JsonSerializerSettings object when calling Deserialize:

var settings = custDefualtSettings();
settings.Converters.Add(new CustomerExtensionsConverter());
result = JsonConvert.DeserializeObject<Customer>(response, settings);

I haven't tested this, but it should give you a general idea of what the implementation would look like.



Related Topics



Leave a reply



Submit