0

Suppose I have these classes:

public class Bar
{
    public Foo MyFoo { get; set; }
}

public class Foo
{
    public string[] Stuff { get; set; }
}

And I have this JSON structure:

{
  "MyFoo":
  {
    "Stuff":"those,are,my,stuff"
  }
}

And I have a code path where a JObject is being converted to Bar using code like below:

myJObject.ToObject(typeof(Bar))

Now what I need to do is to supply the ToObject with a custom serializer to convert the string property Stuff into an array of string (using string.Split(...).ToArray())

I was asked not to add attributes on the client class 'Bar' so after looking around it seemed like a ContractResolver is in order but the issue is that the resolver only lets me handle direct properties of the root Type, that is Bar in my example, and I can't register a JsonConverter on a nested property.

So my question to you guys is, is this even achievable using Json.net?

  • Note that I need to do this not only for the Bar class but to an unlimited amount of classes with unknown structure so I can't hard-code a solution that will work for one type of class.
Brian Rogers
  • 125,747
  • 31
  • 299
  • 300
  • Check the solution here: https://stackoverflow.com/questions/19581820/how-to-convert-json-array-to-list-of-objects-in-c-sharp – sam Mar 09 '20 at 16:25
  • Is updating the JSON source to contain an actual JSON array instead of a comma separated string out of the question? – devNull Mar 09 '20 at 16:29

1 Answers1

0

Based on your description, I don't see why you would need a ContractResolver. You know that the properties you want to deserialize specially will always be of type string[], so just make a converter that handles that type. Maybe something like this:

public class CsvStringConverter : JsonConverter
{
    public override bool CanConvert(Type objectType)
    {
        return objectType == typeof(string[]);
    }

    public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
    {
        JToken token = JToken.Load(reader);

        if (token.Type == JTokenType.Null) 
            return null;

        if (token.Type == JTokenType.String)
            return ((string)token).Split(',');

        if (token.Type == JTokenType.Array) 
            return token.ToObject<string[]>(serializer);

        throw new JsonException("Unexpected token type: " + token.Type);
    }

    public override bool CanWrite => false;

    public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
    {
        throw new NotImplementedException();
    }
}

Then, to use it with your JObject, create a new JsonSerializer instance, add the converter to it, and pass the serializer to the ToObject() method like this:

var serializer = new JsonSerializer();
serializer.Converters.Add(new CsvStringConverter());

var bar = myJObject.ToObject<Bar>(serializer);

Working demo here: https://dotnetfiddle.net/qmeBoh

Brian Rogers
  • 125,747
  • 31
  • 299
  • 300