Sourcecode to showcase the issue: https://github.com/Snuffsis/ConverterExample
So I have an issue that is exactly the same as in this stackoverflow question:
C# Newtonsoft.Json Custom Deserializer
And while that answer does help for properties that are simple types (int, bool, string etc) it doesn't work when there needs to be a nested object. As it throws an exception for Newtonsoft.Json.JsonSerializationException: Self referecing loop detected for property 'Value' with type ...
where the type is the json object, in this case soBillingContact.
It should be able to handle these two JSON formats
Example:
{
"printNoteOnInternalDocuments": {
"value": true
},
"soBillingContact": {
"value": {
"overrideContact": {
"value": true
},
"name": {
"value": "string"
},
"attention": {
"value": "string"
},
"email": {
"value": "string"
},
"web": {
"value": "string"
},
"phone1": {
"value": "string"
},
"phone2": {
"value": "string"
},
"fax": {
"value": "string"
}
}
}
}
{
"printNoteOnInternalDocuments": true,
"soBillingContact": {
"overrideContact": true,
"contactId": 0,
"name": "string",
"attention": "string",
"email": "string",
"web": "string",
"phone1": "string",
"phone2": "string",
"fax": "string"
}
}
The solution in the linked question works fine for the object itself if i create the object as a root. It's only when it's a nested object that it becomes a problem.
I am trying to avoid having to write a custom converter for each json object that exists, and instead try to make a generic one. Which is probably my issue and maybe should be abandoned. But just checking if anyone might have any ideas for a solution.
And aside from that solution above, I have written my own converters that does similar stuff which works fine. Along with custom converter for each specific nested objects, which also works fine.
This is the code that i made myself that works when its for a specific object:
Main
:
static void Main(string[] args)
{
var vSalesOrder = new SalesOrder()
{
Project = 1,
PrintDescriptionOnInvoice = true,
PrintNoteOnExternalDocuments = true,
SoBillingContact = new Contact
{
Attention = "attention",
Email = "@whatever.se",
Fax = "lolfax"
}
};
var jsonString = JsonConvert.SerializeObject(vSalesOrder);
}
Expected output after this should have similar structure as the json above, except for the few properties that have been left out.
SalesOrder
Class:
WrapWithValueConverter code can be found in the linked overflow question at the top.
public class SalesOrder
{
[JsonProperty("project", NullValueHandling = NullValueHandling.Ignore)]
[JsonConverter(typeof(WrapWithValueConverter<int?>))]
public int? Project { get; set; }
[JsonProperty("printDescriptionOnInvoice", NullValueHandling = NullValueHandling.Ignore)]
[JsonConverter(typeof(WrapWithValueConverter<bool>))]
public bool PrintDescriptionOnInvoice { get; set; }
[JsonProperty("printNoteOnExternalDocuments", NullValueHandling = NullValueHandling.Ignore)]
[JsonConverter(typeof(WrapWithValueConverter<bool>))]
public bool PrintNoteOnExternalDocuments { get; set; }
[JsonProperty("printNoteOnInternalDocuments", NullValueHandling = NullValueHandling.Ignore)]
[JsonConverter(typeof(WrapWithValueConverter<bool>))]
public bool PrintNoteOnInternalDocuments { get; set; }
[JsonProperty("soBillingContact", NullValueHandling = NullValueHandling.Ignore)]
[JsonConverter(typeof(ContactDtoJsonConverter))]
public Contact SoBillingContact { get; set; }
}
ContactDtoJsonConverter
Class:
public class ContactDtoJsonConverter : JsonConverter<Contact>
{
public override bool CanRead => false;
public override bool CanWrite => true;
public override Contact ReadJson(JsonReader reader, Type objectType, Contact existingValue, bool hasExistingValue, JsonSerializer serializer)
{
throw new NotImplementedException();
}
public override void WriteJson(JsonWriter writer, Contact value, JsonSerializer serializer)
{
var dtoContact = new DtoContact
{
Value = value
};
JToken t = JToken.FromObject(dtoContact);
JObject o = (JObject)t;
o.WriteTo(writer);
}
}
DtoContact
Class:
public class DtoContact
{
[JsonProperty("value", NullValueHandling = NullValueHandling.Ignore)]
public Contact Value { get; set; }
}
Contact
Class:
public class Contact
{
[JsonProperty("overrideContact", NullValueHandling = NullValueHandling.Ignore)]
public bool OverrideContact { get;set; }
[JsonProperty("attention", NullValueHandling = NullValueHandling.Ignore)]
[JsonConverter(typeof(StringDtoJsonConverter))]
public string Attention { get; set; }
[JsonProperty("email", NullValueHandling = NullValueHandling.Ignore)]
[JsonConverter(typeof(StringDtoJsonConverter))]
public string Email { get; set; }
[JsonProperty("fax", NullValueHandling = NullValueHandling.Ignore)]
[JsonConverter(typeof(StringDtoJsonConverter))]
public string Fax { get; set; }
[JsonProperty("name", NullValueHandling = NullValueHandling.Ignore)]
[JsonConverter(typeof(StringDtoJsonConverter))]
public string Name { get; set; }
[JsonProperty("phone1", NullValueHandling = NullValueHandling.Ignore)]
[JsonConverter(typeof(StringDtoJsonConverter))]
public string Phone1 { get; set; }
[JsonProperty("phone2", NullValueHandling = NullValueHandling.Ignore)]
[JsonConverter(typeof(StringDtoJsonConverter))]
public string Phone2 { get; set; }
[JsonProperty("web", NullValueHandling = NullValueHandling.Ignore)]
[JsonConverter(typeof(StringDtoJsonConverter))]
public string Web { get; set; }
}
StringDtoJsonConverter
Class:
public class StringDtoJsonConverter : JsonConverter<string>
{
public override string ReadJson(JsonReader reader, Type objectType, string existingValue, bool hasExistingValue, JsonSerializer serializer)
{
return (string)reader.Value;
}
public override void WriteJson(JsonWriter writer, string value, JsonSerializer serializer)
{
JToken t = JToken.FromObject(value);
if (t.Type != JTokenType.Object)
{
var dtoValue = new DtoString
{
Value = value
};
serializer.Serialize(writer, dtoValue);
}
}
}