Skip to content

Instantly share code, notes, and snippets.

@nickwesselman
Last active October 27, 2021 20:53
Show Gist options
  • Save nickwesselman/b4958828a8a8e5e3656ce8dbc8ebcdc0 to your computer and use it in GitHub Desktop.
Save nickwesselman/b4958828a8a8e5e3656ce8dbc8ebcdc0 to your computer and use it in GitHub Desktop.
.NET 6 System.Text.Json.Nodes and System.Text.Json source generation, with top-level statements
using System.Diagnostics;
using System.Text.Json;
using System.Text.Json.Nodes;
using System.Text.Json.Serialization;
/*
Testing out .NET 6 JSON DOM for "late binding" of models to a document with unknown structure.
Also added source generation for JSON deserialization, both for the base model and the "late bound" model.
{
"name": "Nick",
"pets": [
{
"name": "Moon",
"type": "Cat",
"attributes": {
"ownsTheHouse": true
}
},
{
"name": "Melody",
"type": "Dog",
"attributes": {
"isAGoodDog": true
}
}
]
}
*/
var jsonString = "{\r\n \"name\": \"Nick\",\r\n \"pets\": [\r\n {\r\n \"name\": \"Moon\",\r\n \"type\": \"Cat\",\r\n \"attributes\": {\r\n \"ownsTheHouse\": true\r\n }\r\n },\r\n {\r\n \"name\": \"Melody\",\r\n \"type\": \"Dog\",\r\n \"attributes\": {\r\n \"isAGoodDog\": true\r\n }\r\n }\r\n ]\r\n}";
var jsonOptions = new JsonSerializerOptions
{
PropertyNamingPolicy = JsonNamingPolicy.CamelCase,
};
jsonOptions.AddContext<PersonJsonContext>(); // represents our base model
var lateBoundOptions = new JsonSerializerOptions
{
PropertyNamingPolicy = JsonNamingPolicy.CamelCase,
};
lateBoundOptions.AddContext<MyJsonContext>(); // SDK consumers could provide as perf benefit
var stopwatch = new Stopwatch();
stopwatch.Start();
var person = JsonSerializer.Deserialize<Person>(jsonString, jsonOptions);
Console.WriteLine($"hello {person?.Name}");
foreach (var pet in person.Pets)
{
Console.WriteLine($"hello {pet.Name} you {pet.Type}!");
switch (pet.Type.ToLowerInvariant())
{
case "dog":
Console.WriteLine($"Are you a good dog? {pet.Attributes["isAGoodDog"]}");
var dog = pet.Attributes.Deserialize<Dog>(lateBoundOptions);
if (dog.IsAGoodDog)
{
Console.WriteLine("You really are a good dog!");
}
break;
case "cat":
Console.WriteLine($"Does the kitty own the house? {pet.Attributes["ownsTheHouse"]}");
var cat = pet.Attributes.Deserialize<Cat>(lateBoundOptions);
if (cat.OwnsTheHouse)
{
Console.WriteLine("It's your house.");
}
break;
}
}
stopwatch.Stop();
Console.WriteLine($"Done in {stopwatch.ElapsedMilliseconds}ms");
public class Person
{
public string Name { get; set; }
public Pet[] Pets { get; set; }
}
public class Pet
{
public string Name { get; set; }
public string Type { get; set;}
public JsonObject Attributes { get; set; }
}
public class Dog
{
public bool IsAGoodDog { get; set;}
}
public class Cat
{
public bool OwnsTheHouse { get; set; }
}
// Attempt to optimize deserialization
// https://devblogs.microsoft.com/dotnet/try-the-new-system-text-json-source-generator/
[JsonSerializable(typeof(Person), GenerationMode = JsonSourceGenerationMode.Metadata)]
internal partial class PersonJsonContext : JsonSerializerContext
{
}
// SDK consumers could create their own and provide to us as perf optimization
[JsonSerializable(typeof(Dog), GenerationMode = JsonSourceGenerationMode.Metadata)]
[JsonSerializable(typeof(Cat), GenerationMode = JsonSourceGenerationMode.Metadata)]
internal partial class MyJsonContext : JsonSerializerContext
{
}
/* OUTPUT
hello Nick
hello Moon you Cat!
Does the kitty own the house? true
It's your house.
hello Melody you Dog!
Are you a good dog? true
You really are a good dog!
*/
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment