Reputation: 51
I have a list of objects (resultList) with a json root (testRoot) which needs to be serialized into json string. The list contains instances (TypeA, B, C) of different types which have their own serializerSettings.
How to implement a custom JsonConverter / JsonSerializerSettings so that when I call JsonConvert.SerializeObject(testRoot), it should serialize each instance based on settings from that instance.
I am unable to find a good solution to my problem. Appreciate your help.
class TypeA
{
public string Name { get; set; }
public int intPropertyA { get; set; }
public string strPropertyA { get; set; }
public JsonSerializerSettings serializerSettingsA { get; set; }
}
class TypeB
{
public string Name { get; set; }
public int intPropertyB { get; set; }
public string strPropertyB { get; set; }
public JsonSerializerSettings serializerSettingsB { get; set; }
}
class TypeC
{
public string Name { get; set; }
public int intPropertyC { get; set; }
public string strPropertyC { get; set; }
public JsonSerializerSettings serializerSettingsC { get; set; }
}
static void Main(string[] args)
{
object[] resultList = new object[3];
int i = 0;
TypeA objA = new TypeA(); // assume all values initialized
TypeB objB = new TypeB(); // assume all values initialized
TypeC objC = new TypeC(); // assume all values initialized
resultList[i++] = new
{
Name = objA.Name,
IntValue = objA.intPropertyA,
StringValue = objA.strPropertyA
};
resultList[i++] = new
{
Name = objB.Name,
IntValue = objB.intPropertyB,
StringValue = objB.strPropertyB
};
resultList[i++] = new
{
Name = objC.Name,
IntValue = objC.intPropertyC,
StringValue = objC.strPropertyC
};
object testRoot = new
{
Test = "All the test results",
date = "",
Results = resultList
};
// How to customize the JsonSerializerSettings/JsonConverter so that, while serializing each type it should use settings from that instace.
string jsonStr = JsonConvert.SerializeObject(testRoot);
}
public class CompositeSerializerSettings : Newtonsoft.Json.JsonSerializerSettings
{
public CompositeSerializerSettings()
{
}
}
public class CompositeJsonConverter : Newtonsoft.Json.JsonConverter
{
public override bool CanConvert(Type objectType)
{
throw new NotImplementedException();
}
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
{
throw new NotImplementedException();
}
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
{
throw new NotImplementedException();
}
}
Upvotes: 0
Views: 6108
Reputation: 73293
As I noted in a comment above, this doesn't exactly answer your question, because in your test code you don't pass instances of TypeA or TypeB or TypeC, you pass anonymous objects derived from those classes.
However, if you are actually trying to serialize the objects themselves rather than anonymous objects, and want the serializer to use custom settings for each type, you have to tell it how to find them.
Using an interface is one option: note you have to 'ignore' the settings, or they appear in the serialized output - also I have set the indentation purely to show this is working.
public interface ISerializerSettings
{
JsonSerializerSettings serializerSettings { get;}
}
class TypeA : ISerializerSettings
{
public string Name { get; set; }
public int intPropertyA { get; set; }
public string strPropertyA { get; set; }
[JsonIgnore]
public JsonSerializerSettings serializerSettings { get; } = new JsonSerializerSettings
{
Formatting = Formatting.Indented
};
}
class TypeB : ISerializerSettings
{
public string Name { get; set; }
public int intPropertyB { get; set; }
public string strPropertyB { get; set; }
[JsonIgnore]
public JsonSerializerSettings serializerSettings { get; } = new JsonSerializerSettings
{
Formatting = Formatting.None
};
}
class TypeC : ISerializerSettings
{
public string Name { get; set; }
public int intPropertyC { get; set; }
public string strPropertyC { get; set; }
[JsonIgnore]
public JsonSerializerSettings serializerSettings { get; } = new JsonSerializerSettings
{
Formatting = Formatting.Indented
};
}
Then in the converter, use the type's settings:
public class CompositeJsonConverter : JsonConverter
{
public override bool CanConvert(Type objectType)
{
return typeof(ISerializerSettings).IsAssignableFrom(objectType);
}
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
{
throw new NotImplementedException();
}
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
{
writer.WriteRaw(JsonConvert.SerializeObject(value, ((ISerializerSettings)value).serializerSettings));
}
}
Finally, in your program, tell the serializer to use your converter:
string jsonStr = JsonConvert.SerializeObject(testRoot, new CompositeJsonConverter());
Given this input:
TypeA objA = new TypeA(); // assume all values initialized
TypeB objB = new TypeB(); // assume all values initialized
TypeC objC = new TypeC(); // assume all values initialized
object[] resultList = new object[] {
objA, objB, objC
};
object testRoot = new
{
Test = "All the test results",
date = "",
Results = resultList
};
string jsonStr = JsonConvert.SerializeObject(testRoot, new CompositeJsonConverter());
This is the output: note that TypeB has no formatting, but the others do:
{"Test":"All the test results","date":"","Results":[{
"Name": null,
"intPropertyA": 0,
"strPropertyA": null
}{"Name":null,"intPropertyB":0,"strPropertyB":null}{
"Name": null,
"intPropertyC": 0,
"strPropertyC": null
}]}
Upvotes: 1