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
C# - How to Iterate Through Classes Fields and Set Properties
Mvvm: Binding to Model While Keeping Model in Sync with a Server Version
How to Find the Fully Qualified Name of an Assembly
How to Get Mx Records for a Dns Name with System.Net.Dns
How to Split an Ienumerable into Two by a Boolean Criteria Without Two Queries
Check If All Items Are the Same in a List
Casting Object to Int Throws Invalidcastexception in C#
How to Implement Custom Authentication in ASP.NET MVC 5
Why Is There Huge Performance Hit in 2048X2048 Versus 2047X2047 Array Multiplication
How to Convert a Class into Dictionary<String,String>
Loading Image from Code Using Relative Path in Windows Forms
C# Reflection - Load Assembly and Invoke a Method If It Exists