0

I've created an API endpoint that is receiving a List of objects. The 'AttributeValue' of the objects could be either a string or an int. Here is a generic version of my code:

public class b
{
  public List<a> myList {get; set;} = new List<a>();
}

public class a
{
   public object AttributeValue {get; set;}
}

The problem is, I need to know the original data type. When I check the type it tells me "System.Text.Json.JsonElement". I also tried something like the following:

if(b.myList[0].AttributeValue is int) { do something.. }
else if(b.myList[0].AttributeValue is string) {do something...}
else {throw error}

I always throw an error so I assume I am losing my original data type when I am deserializing. Any ideas what I can do?

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

3 Answers3

2

try to cast to JsonElement

var json="{\"myList\":[{\"AttributeValue\":1},{\"AttributeValue\":\"2\"},{\"AttributeValue\":3},{\"AttributeValue\":\"4\"}]}";

var b =System.Text.Json.JsonSerializer.Deserialize<b>(json);

if (((JsonElement) b.myList[0].AttributeValue).ValueKind.ToString()=="Number") ...
else
 if (((JsonElement) b.myList[1].AttributeValue).ValueKind.ToString()=="String")... 
Serge
  • 40,935
  • 4
  • 18
  • 45
0

you can use Oneof<> nuget.

 OneOf<string, int> result = funcHere(b.myList);
            return result.Match<xxx>(
                stringValue =>
                {
                  // do some string procedure
                },
                intValue =>
                {
                  // do some int procedure
                };

KomiShao
  • 23
  • 5
-1

You can apply a custom JsonConverter<T> similar to the one shown in the documentation to AttributeValue to deserialize to an Int32 or a string depending on the incoming JSON value:

public class a
{
    [JsonConverter(typeof(ObjectPrimitiveConverter))]
    public object AttributeValue {get; set;}
}

public class ObjectPrimitiveConverter : JsonConverter<object>
{
    public override object Read(ref System.Text.Json.Utf8JsonReader reader, Type typeToConvert, System.Text.Json.JsonSerializerOptions options) => 
        reader.TokenType switch
        {
            JsonTokenType.String => reader.GetString(),
            JsonTokenType.Number when reader.TryGetInt32(out var i) => i,
            //Add other cases as needed:
            //JsonTokenType.Number when reader.TryGetInt64(out var l) => l,
            //JsonTokenType.Number when reader.TryGetDouble(out var d) => d,
            //JsonTokenType.True => true,
            //JsonTokenType.False => false,
            _ => throw new JsonException(), // StartObject, StartArray, Null    
        };
    public override void Write(Utf8JsonWriter writer, object value, JsonSerializerOptions options) =>
        JsonSerializer.Serialize(writer, value, value.GetType() /*, options */); // Passing options when ObjectPrimitiveConverter has been added to options.Converters will cause a stack overflow
}

Notes:

  • While the JSON standard does distinguish between strings and numbers, it does not distinguish between integers and decimals that happen to have integer values. Thus if your AttributeValue might contain an integer of value 1 or a double of value 1D, System.Text.Json will serialize both as 1 and, when read back in, you will not be able to distinguish the type.

Demo fiddle here.

dbc
  • 104,963
  • 20
  • 228
  • 340