Class NewtonSoft.Json Serialize and Deserialize with property of type IEnumerable <ISomeInterface>

I am trying to move some code to use the ASP.NET MVC Web API generated by Json data instead of SOAP Xml.

I had a problem with serializing and deserializing type properties:

IEnumerable<ISomeInterface>. 

Here is a simple example:

 public interface ISample{ int SampleId { get; set; } } public class Sample : ISample{ public int SampleId { get; set; } } public class SampleGroup{ public int GroupId { get; set; } public IEnumerable<ISample> Samples { get; set; } } } 

I can easily serialize SampleGroup instances with:

 var sz = JsonConvert.SerializeObject( sampleGroupInstance ); 

However, the corresponding deserialization is not performed:

 JsonConvert.DeserializeObject<SampleGroup>( sz ); 

with this exception message:

"Cannot create an instance of type JsonSerializationExample.ISample. The type is an interface or abstract class and cannot be created."

If I get a JsonConverter, I can decorate my property as follows:

 [JsonConverter( typeof (SamplesJsonConverter) )] public IEnumerable<ISample> Samples { get; set; } 

Here is the JsonConverter:

 public class SamplesJsonConverter : JsonConverter{ public override bool CanConvert( Type objectType ){ return ( objectType == typeof (IEnumerable<ISample>) ); } public override object ReadJson( JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer ){ var jA = JArray.Load( reader ); return jA.Select( jl => serializer.Deserialize<Sample>( new JTokenReader( jl ) ) ).Cast<ISample>( ).ToList( ); } public override void WriteJson( JsonWriter writer, object value, JsonSerializer serializer ){ ... What works here? } } 

This converter solves the problem of deserialization, but I cannot figure out how to code the WriteJson method to serialize again.

Can anyone help?

Is this the "right" way to solve the problem in the first place?

+49
json c # serialization deserialization
Aug 01 2018-12-12T00:
source share
7 answers

You do not need to use JsonConverterAttribute , keep your model clean, and also use CustomCreationConverter , the code is simpler:

 public class SampleConverter : CustomCreationConverter<ISample> { public override ISample Create(Type objectType) { return new Sample(); } } 

Then:

 var sz = JsonConvert.SerializeObject( sampleGroupInstance ); JsonConvert.DeserializeObject<SampleGroup>( sz, new SampleConverter()); 

Documentation: Deserialize with CustomCreationConverter

+57
Aug 01 2018-12-12T00:
source share
β€” -

This is pretty simple and free json.net support, you just need to use the following JsonSettings when serializing and deserializing:

 JsonConvert.SerializeObject(graph,Formatting.None, new JsonSerializerSettings() { TypeNameHandling =TypeNameHandling.Objects, TypeNameAssemblyFormat = System.Runtime.Serialization.Formatters.FormatterAssemblyStyle.Simple }); 

and for Deserialzing use the code below:

 JsonConvert.DeserializeObject(Encoding.UTF8.GetString(bData),type, new JsonSerializerSettings(){TypeNameHandling = TypeNameHandling.Objects} ); 

Just pay attention to the JsonSerializerSettings object initializer, which is important to you.

+14
Jan 14 '14 at 9:57
source share

I solved this problem using a special parameter for JsonSerializerSettings called TypeNameHandling.All

The TypeNameHandling parameter includes type information for JSON serialization and read type information to create creation types during JSON deserialization

Serialization:

 var settings = new JsonSerializerSettings { TypeNameHandling = TypeNameHandling.All }; var text = JsonConvert.SerializeObject(configuration, settings); 

Deserialization:

 var settings = new JsonSerializerSettings { TypeNameHandling = TypeNameHandling.All }; var configuration = JsonConvert.DeserializeObject<YourClass>(json, settings); 

The YourClass class can have any type of base type, and it will be correctly serialized.

+7
Nov 02 '16 at 15:11
source share

Great solution, thanks! I took the AndyDBell question and Cuong Le answer to build an example with two interface options:

 public interface ISample { int SampleId { get; set; } } public class Sample1 : ISample { public int SampleId { get; set; } public Sample1() { } } public class Sample2 : ISample { public int SampleId { get; set; } public String SampleName { get; set; } public Sample2() { } } public class SampleGroup { public int GroupId { get; set; } public IEnumerable<ISample> Samples { get; set; } } class Program { static void Main(string[] args) { //Sample1 instance var sz = "{\"GroupId\":1,\"Samples\":[{\"SampleId\":1},{\"SampleId\":2}]}"; var j = JsonConvert.DeserializeObject<SampleGroup>(sz, new SampleConverter<Sample1>()); foreach (var item in j.Samples) { Console.WriteLine("id:{0}", item.SampleId); } //Sample2 instance var sz2 = "{\"GroupId\":1,\"Samples\":[{\"SampleId\":1, \"SampleName\":\"Test1\"},{\"SampleId\":2, \"SampleName\":\"Test2\"}]}"; var j2 = JsonConvert.DeserializeObject<SampleGroup>(sz2, new SampleConverter<Sample2>()); //Print to show that the unboxing to Sample2 preserved the SampleName values foreach (var item in j2.Samples) { Console.WriteLine("id:{0} name:{1}", item.SampleId, (item as Sample2).SampleName); } Console.ReadKey(); } } 

And the general version for SampleConverter:

 public class SampleConverter<T> : CustomCreationConverter<ISample> where T: new () { public override ISample Create(Type objectType) { return ((ISample)new T()); } } 
+4
Jul 16 '13 at 15:22
source share

In my projects, this part of the code always worked as the default serializer, which serializes the specified value, as if there was no special converter:

 serializer.Serialize(writer, value); 
+2
Aug 01 2018-12-12T00:
source share

I got this to work:

explicit conversion

  public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer) { var jsonObj = serializer.Deserialize<List<SomeObject>>(reader); var conversion = jsonObj.ConvertAll((x) => x as ISomeObject); return conversion; } 
+1
Feb 20 '13 at 11:17
source share

After that:

 public interface ITerm { string Name { get; } } public class Value : ITerm... public class Variable : ITerm... public class Query { public IList<ITerm> Terms { get; } ... } 

I managed to convert a trick implementing this:

 public class TermConverter : JsonConverter { public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer) { var field = value.GetType().Name; writer.WriteStartObject(); writer.WritePropertyName(field); writer.WriteValue((value as ITerm)?.Name); writer.WriteEndObject(); } public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer) { var jsonObject = JObject.Load(reader); var properties = jsonObject.Properties().ToList(); var value = (string) properties[0].Value; return properties[0].Name.Equals("Value") ? (ITerm) new Value(value) : new Variable(value); } public override bool CanConvert(Type objectType) { return typeof (ITerm) == objectType || typeof (Value) == objectType || typeof (Variable) == objectType; } } 

This allows me to serialize and deserialize to JSON, for example:

 string JsonQuery = "{\"Terms\":[{\"Value\":\"This is \"},{\"Variable\":\"X\"},{\"Value\":\"!\"}]}"; ... var query = new Query(new Value("This is "), new Variable("X"), new Value("!")); var serializeObject = JsonConvert.SerializeObject(query, new TermConverter()); Assert.AreEqual(JsonQuery, serializeObject); ... var queryDeserialized = JsonConvert.DeserializeObject<Query>(JsonQuery, new TermConverter()); 
0
Feb 21 '16 at 17:20
source share



All Articles