0

I get this json format from an API:

"url_service": "",
"Description": null,
"Target": "5,6",
"Category ": "2"

I'm trying to deserialize the json into a model. The trouble is with the "Target" field which is supposed to be an ICollection of int. Here is my model:

public string Description{ get; set; }
public ICollection<int> Target{ get; set; }
public int Category { get; set; }

Is there a way to process the Json before it gets serialised in order to make a collection out of the comma separated string?

maccettura
  • 10,514
  • 3
  • 28
  • 35
  • 2
    If you use Newtonsoft, you'll probably need to create your own [JsonConverter](https://www.newtonsoft.com/json/help/html/CustomJsonConverter.htm) – Luis Lavieri Apr 25 '18 at 20:14

4 Answers4

1

Instead of trying to change the deserialization logic, why not make it easier on yourself and just include a new property in your model?

public string Description{ get; set; }
public int Category { get; set; }

//Change this back to string, since that is what your JSON is
public string Target{ get; set; }

//Add a "TargetList" property that just reads from "Target" and turns into a List
public List<int> TargetList => Target.Split(',').Select(x => int.Parse(x)).ToList();

Be aware that there is no error handling in my code so you will have to modify accordingly.

maccettura
  • 10,514
  • 3
  • 28
  • 35
0

Yes, have your C# class implement the ISerializable interface. There are OnDeserialized(), OnSerialized() functions you could implement.

Refer to .NET Deserialisation with OnDeserializing and OnDeserialized

T McKeown
  • 12,971
  • 1
  • 25
  • 32
0

Your JSON fragment does not describe a collection of integers but a string. The correct one would be

"Target": [ 5, 6 ],

which translates into a JSON schema of

 "Target": {
     "type": ["array"],
     "items": { "type": "integer"}
    },

If you don't have control of the result then create another property which will be a result of integers such as

   private string _target;
   public string Target {  get { return _target; } 
                           set { 
                                 _target = value; 
                                 Targets = Regex.Matches(_target, @"(\d+)")
                                                .OfType<Match>()
                                                .Select(mt => int.Parse(mt.Value))
                                                .ToList();
   public List<int> Targets { get; set; }
ΩmegaMan
  • 29,542
  • 12
  • 100
  • 122
0

The Target field is of string type in your json, hence the serialiser will attempt to read it as a string. You can use a converter to overrule that, for example using Newtonsoft Json.

Let's assume your data structure to be defined as follows:

public class Data {
    public string Description{ get; set; }
    public ICollection<int> Target{ get; set; }
    public int Category { get; set; }
}

Then you may create your own JsonConverter as follows:

public class DataConverter : JsonConverter {

    public override bool CanWrite => false;

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

    public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer) {

        var jObject = JObject.Load(reader);

        var data = new Data();

        if (jObject.TryGetValue("Description", out JToken jDescription)) {
            data.Description = jDescription.Value<string>();
        }
        if (jObject.TryGetValue("Target", out JToken jTarget)) {
            data.Target = ToTarget(jTarget, serializer);
        }
        if (jObject.TryGetValue("Category", out JToken jCategory)) {
            data.Category = jCategory.Value<int>();
        }

        return req;

    }

    private static ICollection<int> ToTarget( JToken jTarget, JsonSerializer serializer ) {

        int defaultValue = -1;
        var target = new List<int>();
        var collection = jTarget.Value<string>().Split(',');
        foreach (string str in collection)
            if (int.TryParse(str, out int number))
                target.Add(number);
            else
                target.Add(defaultValue);

        return target;

    }

    public override bool CanConvert(Type objectType) => objectType == typeof(Data);

}

You can then deserialise using the following code:

var jsonSettings = new JsonSerializerSettings();
jsonSettings.Converters.Add(new DataConverter);
Data data = JsonConvert.DeserializeObject<Data>(yourJsonString, jsonSettings);

Further considerations: this approach provides clear separation between your data definition and the data parsing logic, hence keeping your data structure and definition clean from any json specific information and parsing logic.

smn.tino
  • 2,272
  • 4
  • 32
  • 41