System.Text.Json.JsonElement ToObject workaround
.net-core-3.0, c#, system.text.json
Solution
In .NET 6, extension methods were added to `JsonSerializer` to deserialize an object directly from a `JsonElement` or `JsonDocument`:
public static partial class JsonSerializer
{
public static TValue? Deserialize<TValue>(this JsonDocument document, JsonSerializerOptions? options = null);
public static object? Deserialize(this JsonDocument document, Type returnType, JsonSerializerOptions? options = null);
public static TValue? Deserialize<TValue>(this JsonDocument document, JsonTypeInfo<TValue> jsonTypeInfo);
public static object? Deserialize(this JsonDocument document, Type returnType, JsonSerializerContext context);
public static TValue? Deserialize<TValue>(this JsonElement element, JsonSerializerOptions? options = null);
public static object? Deserialize(this JsonElement element, Type returnType, JsonSerializerOptions? options = null);
public static TValue? Deserialize<TValue>(this JsonElement element, JsonTypeInfo<TValue> jsonTypeInfo);
public static object? Deserialize(this JsonElement element, Type returnType, JsonSerializerContext context);
}
Now you will be able to do:
using var jDoc = JsonDocument.Parse(str);
var myClass = jDoc.RootElement.GetProperty("SomeProperty").Deserialize<SomeClass>();
Notes:
`JsonDocument` is disposable. According to the documentation, This class utilizes resources from pooled memory... failure to properly dispose this object will result in the memory not being returned to the pool, which will increase GC impact across various parts of the framework.
So, be sure to declare your `jDoc` with a `using` statement.
The new methods should be present in .NET 6.0 Preview RC1.
They were added in response to the enhancement request We should be able serialize and serialize from DOM #31274, which has been closed.
Similar extension methods were added for the new `JsonNode` mutable JSON document node as well
public static TValue? Deserialize<TValue>(this JsonNode? node, JsonSerializerOptions? options = null)
public static object? Deserialize(this JsonNode? node, Type returnType, JsonSerializerOptions? options = null)
public static TValue? Deserialize<TValue>(this JsonNode? node, JsonTypeInfo<TValue> jsonTypeInfo)
public static object? Deserialize(this JsonNode? node, Type returnType, JsonSerializerContext context)
In .NET 5 and earlier these methods do not exist. As a workaround, you may get better performance by writing to an intermediate `byte` buffer rather than to a string, since both `JsonDocument` and `Utf8JsonReader` work directly with `byte` spans rather than strings or `char` spans. As stated in the documentation:
Serializing to UTF-8 is about 5-10% faster than using the string-based methods. The difference is because the bytes (as UTF-8) don't need to be converted to strings (UTF-16).
public static partial class JsonExtensions
{
public static T ToObject<T>(this JsonElement element, JsonSerializerOptions options = null)
{
var bufferWriter = new ArrayBufferWriter<byte>();
using (var writer = new Utf8JsonWriter(bufferWriter))
element.WriteTo(writer);
return JsonSerializer.Deserialize<T>(bufferWriter.WrittenSpan, options);
}
public static T ToObject<T>(this JsonDocument document, JsonSerializerOptions options = null)
{
if (document == null)
throw new ArgumentNullException(nameof(document));
return document.RootElement.ToObject<T>(options);
}
}
A demo fiddle is here.
Problem
I want to know the equivalent of the `ToObject<>()` method in Json.NET for System.Text.Json. Using Json.NET you can use any `JToken` and convert it to a class. For example: ``` var str = ""; // Some JSON string var jObj = JObject.Parse(str); var myClass = jObj["SomeProperty"].ToObject<SomeClass>(); ``` How would we be able to do this with .NET Core 3's new `System.Text.Json`? ``` var str = ""; // Some JSON string var jDoc = JsonDocument.Parse(str); var myClass = jDoc.RootElement.GetProperty("SomeProperty"). <-- now what?? ``` Initially, I was thinking I'd just convert the `JsonElement` that is returned in `jDoc.RootElement.GetPRoperty("SomeProperty")` to a string and then deserialize that string. But I feel that might not be the most efficient method, and I can't really find documentation on doing it another way.