3

I receive a series of json files which are not standarized, and a specific field is always a number, but sometimes quoted and sometimes unquoted.

e.g: sometimes:

{
  "skinname": "Classic Red",
  "drivername": "",
  "country": "",
  "team": "",
  "number": "0",
  "priority": 4
}

sometimes:

{
    "skinname": "Racing 125",
    "drivername": "",
    "country": "",
    "team" : "Audi Motorsport",
    "number": 125
}

And worst case:

{
  "skinname": "",
  "drivername": "",
  "country": "",
  "team": "",
  "number": "",
  "priority": 1
}

I use System.Text.Json.JsonSerializer.Deserialize<>(), deserialized to this class:

public class JsonLiveryDetails
    {
        public string skinname { get; set; }
        public string drivername { get; set; }
        public string country { get; set; }
        public string team { get; set; }
        public string number { get; set; }
        public int? priority { get; set; }
    }

I have a class to deserialize into, but of course, sometimes I get an error whether I assign that value as string or int.

I cant't get to handle it in the get; set; of the field, so I workarounded it by catching the error, trying to deserialize it into a class with the other type and then convert the second class into the first, or catching a final error...

I find my workaround dirty, maybe (probabliy) there is a better way to handle it.

EDIT: Following Serge comments, added more details. EDIT2: Found another case, where number is "" and makes proposed solution to fail

alexddf
  • 53
  • 5
  • 3
    You have to post what a json serializer you are using, and a coulple of different jsons and class you are using to deserialize. Just forget about Text.Json and use Newtonsoft.Json and you will never get any error – Serge Apr 01 '23 at 00:05
  • Please provide a [mcve] – NineBerry Apr 01 '23 at 00:06
  • edited to add asked details – alexddf Apr 01 '23 at 00:20
  • Does this answer your question? [System.Text.Json: Deserialize JSON with automatic casting](https://stackoverflow.com/questions/59097784/system-text-json-deserialize-json-with-automatic-casting) – NineBerry Apr 01 '23 at 00:45

2 Answers2

2

you can try this converter

JsonLiveryDetails details = JsonSerializer.Deserialize<JsonLiveryDetails>(json);

public class IntToStringConverter : System.Text.Json.Serialization.JsonConverter<string>
{
    public override string Read(ref Utf8JsonReader reader, Type type, JsonSerializerOptions options)
    {
        if (reader.TokenType == JsonTokenType.Number)
             return  reader.GetInt32().ToString();
      
        return reader.GetString();
    }
   
    public override void Write(Utf8JsonWriter writer, string value, JsonSerializerOptions options)
    {
        writer.WriteStringValue(value.ToString());
    }
}

public class JsonLiveryDetails
{
    public string skinname { get; set; }
    public string drivername { get; set; }
    public string country { get; set; }
    public string team { get; set; }
    [System.Text.Json.Serialization.JsonConverter(typeof(IntToStringConverter))]
    public string number { get; set; }
    public int? priority { get; set; }
}

or maybe it make sense to change number property type to int

public class StringToIntConverter : System.Text.Json.Serialization.JsonConverter<int?>
{
    public override int? Read(ref Utf8JsonReader reader, Type type, JsonSerializerOptions options)
    {
        if (reader.TokenType == JsonTokenType.String)
        {
            var str = reader.GetString();

            if (!string.IsNullOrEmpty(str)
              && int.TryParse(str, out int val)) return val;
            else return default(int?);
        }
        return reader.GetInt32();
    }

    public override void Write(Utf8JsonWriter writer, int? value, JsonSerializerOptions options)
    {
        if (value != null)
            writer.WriteNumberValue((int)value);
            else writer.WriteNullValue();
    }
}

public class JsonLiveryDetails
{
    public string skinname { get; set; }
    public string drivername { get; set; }
    public string country { get; set; }
    public string team { get; set; }
[System.Text.Json.Serialization.JsonConverter(typeof(StringToIntConverter))]
    public int? number { get; set; }
    public int? priority { get; set; }
}
Serge
  • 40,935
  • 4
  • 18
  • 45
0

Declare the property as int and use the JsonNumberHandling attribute on the class or individual property to allow automatic casting from string to integer.

[JsonNumberHandling(JsonNumberHandling.AllowReadingFromString)]
public class JsonLiveryDetails
{
    public string skinname { get; set; }
    public string drivername { get; set; }
    public string country { get; set; }
    public string team { get; set; }
    public int number { get; set; }
    public int? priority { get; set; }
}

See Serge's answer in order to be able to also handle empty strings.

NineBerry
  • 26,306
  • 3
  • 62
  • 93