In order to ask my question, I will be referring to @Brian Rogers 's answer here. In this answer ReadJson is doing something relatively simple. How could I however add a layer in there in order to manipulate the incoming Json string before deserialising it into an object and then returning it?
Here is the type of things I would like to do (modified version of Brian's WrappedObjectConvert class):
class WrappedObjectConverter : JsonConverter
{
private string CustomParsing(string jsonString)
{
string modifiedJsonString;
// Some renaming
modifiedJsonString= Regex.Replace(modifiedJsonString, $@"(?<="")CarName(?="":\s)", "Myname", RegexOptions.IgnoreCase);
modifiedJsonString= Regex.Replace(modifiedJsonString, $@"(?<="")CustName(?="":\s)", "Myname", RegexOptions.IgnoreCase);
modifiedJsonString= Regex.Replace(modifiedJsonString, $@"(?<="")MyName(?="":\s)", "Myname", RegexOptions.IgnoreCase);
modifiedJsonString= Regex.Replace(modifiedJsonString, $@"(?<="")SomeAddr(?="":\s)", "AddressLine1 ", RegexOptions.IgnoreCase);
// Renaming IsPublic true/false to IsPrivate false/true
modifiedJsonString= Regex.Replace(modifiedJsonString, "\"IsPublic\": true,", "\"IsPrivate\": false,", RegexOptions.IgnoreCase);
modifiedJsonString = Regex.Replace(modifiedJsonString, "\"IsPublic\": false,", "\"IsPrivate\": true,", RegexOptions.IgnoreCase);
}
public override bool CanConvert(Type objectType)
{
return true;
}
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
{
JToken token = JToken.Load(reader);
string modifiedJsonString = CustomParsing(token.ToString());
return ????; // How to return the object
// I could do something of the sort, but not sure it's got its place here:
// return JsonConvert.DeserializeObject<RootObject>(modifiedJsonString );
}
public override bool CanWrite
{
get { return false; }
}
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
{
throw new NotImplementedException();
}
}
The client class has also been slightly modified by adding the field "IsPrivate":
public class Client
{
[JsonConverter(typeof(WrappedObjectConverter))]
public List<Product> ProductList { get; set; }
[JsonConverter(typeof(WrappedObjectConverter))]
public string Name { get; set; }
[JsonConverter(typeof(WrappedObjectConverter))]
public bool IsPrivate { get; set; }
[JsonConverter(typeof(WrappedObjectConverter))]
public string AddressLine1 { get; set; }
}
And the demo with a modified Json (some labels have been changed from Brian's example, which need to be parsed and modified):
class Program
{
static void Main(string[] args)
{
string json = @"
{
""Result"": {
""Client"": {
""ProductList"": {
""Product"": [
{
""MyName"": {
""CarName"": ""Car polish"",
""IsPublic"": ""True""
}
}
]
},
""MyName"": {
""CustName"": ""Mr. Clouseau""
},
""AddressLine1"": {
""SomeAddr"": ""Hightstreet 13""
}
}
}
}";
RootObject obj = JsonConvert.DeserializeObject<RootObject>(json);
Client client = obj.Result.Client;
foreach (Product product in client.ProductList)
{
Console.WriteLine(product.Name);
}
Console.WriteLine(client.Name);
Console.WriteLine(client.AddressLine1);
}
}
As you can see, the way the parsing is being done is a bit hacky, so my questions are:
- Can I incorporate this parsing to the classes themselves without making a mess of my classes?
- If my approach is the way to go, how do I recreate the object so that ReadJson() can return it (see question marks in code above)
- Taking it to the next level: If the client class had a constructor taking in arguments (passed to a base class), how would you do 2. (as the extra level of nesting would complicate things I believe)
- If this is the wrong way to go, I am open to suggestions
JsonPathConverter
in the other answer you would only need to decorate those properties that either have a different name than what is in the JSON or which need to be mapped to a child object. But based on your constraints, this converter isn't going to work for you either. It won't handle non-default constructors (as you've seen), and it doesn't have a way to translate true to false and vice versa for theIsPublic
property example. You are going to need a custom converter specifically for your situation. – JermainejermanSerializationBinder
doesn't map JSON properties to class properties, it maps type names and assembly names in the JSON (in a special$type
meta property) to actual types. So that's not going to help you with flattening. – Jermainejerman