How to find out what type a JsonValue is in System.Text.Json
Asked Answered
M

5

20

So when I have a JsonNode I can just ask if it's a JsonObject or a JsonArray and work with those. But when the node is an actual value, how do I know whether it's a string, number or boolean?

Of course I could just try and parse the value, but then a number transmitted in a string would become a number instead of a string which I'd like to avoid.

I'm using System.Text.Json with .NET 6.

Matias answered 23/3, 2022 at 13:18 Comment(6)
Don't the regular C# type checks work? if(someValue is string)..?Superimposed
Tried it an, interestingly, the error says An expression of type System.Text.Json.JsonNode? cannot be handled by a pattern of type 'string'. Not what I expected and not sure what it means exactly, thought a type check would always be possible. Edit: Same for other primitive type checks.Matias
From the source, it looks like a JsonValue just wraps a JsonElement. So you might be able to do .GetValue<JsonElement>() (which passes this check), and the inspect its ValueKind property?Yolanda
Yess this one works, thank you very much!Matias
@Yolanda Put that in an answer then I can checkmark it :)Matias
JsonNodeExtensions.GetValueKind(this JsonNode node, JsonSerializerOptions options = null) from this comment by steveharter to JsonNode feedback #55827 seems to do what you need. (Be sure to click on click for samples to see the code.)Amphibolous
Y
8

From the source, it looks like a JsonValue just wraps a JsonElement. So you can do .GetValue<JsonElement>() (which passes this check), and then inspect its ValueKind property.

Yolanda answered 23/3, 2022 at 15:50 Comment(5)
The source also shows that the underlying value may not be a JsonElement.Nussbaum
"A value of type 'System.Int32' cannot be converted to a 'System.Text.Json.JsonElement'."Capitalism
This does not work. I get the same error as SerGElisabeth
You could just use TryGetValue someObject["SomeNode"].AsValue().TryGetValue<someType>(out someType result)Elisabeth
JsonNodeExtensions.GetValueKind(this JsonNode node, JsonSerializerOptions options = null) from this comment by steveharter to JsonNode feedback #55827 handles both the JsonElement and non-JsonElement cases. (Be sure to click on click for samples to see the code.)Amphibolous
E
7

The accepted answer only works for specific use cases, namely that the node in question is of type JsonValue.

I propose a better option is to first test for the basic kind of types there are in JSON.

someObject["SomeNode"] is JsonArray 
someObject["SomeNode"] is JsonObject
someObject["SomeNode"] is JsonValue

if the object is of type JsonValue one can use tryGetvalue to directly test for the expected value type

someObject["SomeNode"].AsValue().TryGetValue<someType>(out someType result)

TryGetValue returns true if it the value was parseble as the requested type.

If the expected type is completely unknown or variable (ugh), you could use the

someObject["SomeNode"].GetValue<JsonElement>().ValueKind 

trick. But that only works for distinquishing between int and string and the bool values. Trying this on an array will give an exception. Therefore you first have to test with the "is" style syntax above.

Elisabeth answered 20/7, 2022 at 16:3 Comment(1)
As you can see in the first paragraph of the question, something being a JsonObject or JsonArray is already being checked and the question itself is specifically about what to do when it's in fact a JsonValue. Thanks for the complete answer though, might be helpful to people coming through search engines in the future.Matias
V
6

The following code works in .NET fiddle with .NET 6.

Note:

  • if your JsonValue ultimately came from a JsonNode.Parse*(...), then your JsonValue will contain a "JSON type".
  • if your JsonValue was created using JsonValue.Create() or an implicit conversion, then your JsonValue will contain a "CLR type".
  • The following code returns an approximate "CLR type" for "JSON types", because of the next point.
  • JsonValue.GetValue<T>() only does type conversion if JsonValue contains a "JSON type".
  • JsonValue.GetValue<object>() conveniently returns the underlying value, which is a JsonElement if it is a "JSON type".
public static class JsonValueExtensions
{
    public static Type GetValueType(this JsonValue jsonValue)
    {
        var value = jsonValue.GetValue<object>();
        if (value is JsonElement element)
        {
            return element.ValueKind switch
            {
                JsonValueKind.False => typeof(bool),
                JsonValueKind.True => typeof(bool),
                JsonValueKind.Number => typeof(double),
                JsonValueKind.String => typeof(string),
                var _ => typeof(JsonElement),
            };
        }
        return value.GetType();
    }
}
Versify answered 28/1, 2023 at 2:21 Comment(0)
F
3

Depending on the type of JsonElement returned you have to handle it differently.

My case was that the returned element was ValueKind = Array : "[[47.751]]" So in order to get it I did created this method

private object GetValueFromJsonElement(WorkbookRange range)
{
    var element = range.Values.RootElement.EnumerateArray().First()[0];
    switch (element.ValueKind)
    {
        case JsonValueKind.Number:
            return element.GetDouble();

        case JsonValueKind.String:
            return element.GetString();

        case JsonValueKind.True:
        case JsonValueKind.False:
            return element.GetBoolean();
        default:
            throw new InvalidOperationException("The Value Type returned is not handled");
    }
}
Friedlander answered 7/9, 2022 at 9:32 Comment(2)
OP is talking about a JsonObject not a JsonElement...Kindless
@DouglasGaskell If you take a look at the accepted answer, in the source link, you'll see that I'm not so far off topic.Friedlander
D
2

Each JsonProperty has two properties - Name and Value of Type JsonElement. JsonElement has an Enum property named ValueKind which can help you determine what of what data type your JSON value is.

You can get JsonProperties by calling .EnumerateObject() on your JsonElement. You can work with your Json document as a JsonElement instead of JsonObject.

Dimidiate answered 23/3, 2022 at 13:33 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.