How it works
A fixed .NET model is convenient when a payload has a stable schema, but some small tools need to inspect object properties dynamically. EnumerateObject exposes each property's name and JsonElement value. The sample treats the object as a map from names to integer measurements and calculates a total.
Each property value is checked for the Number kind before GetInt32 is called. That check rejects strings, nulls, arrays, and objects, but it does not by itself prove that the numeric token fits the integer range or represents an integer. The typed accessor supplies another boundary that a real parser should handle deliberately.
The output follows this input object's property sequence for inspection. If the application needs a stable sorted report independent of producer order, collect and sort the names explicitly. JSON objects should not be treated as a substitute for an ordered command sequence merely because a particular payload happens to list properties in a useful order.
Dynamic parsing does not remove the need for a schema. It moves the schema checks into code: permitted names, value kinds, ranges, duplicate-name policy, and maximum sizes still need decisions. A permissive loop that accepts every property can unintentionally admit fields that the rest of the application cannot interpret safely.
Practice by adding a string property, a fractional number, and an out-of-range integer in separate inputs. Report each rejected property name without collapsing all errors into one generic total. Then add an allowlist of accepted names and decide whether unknown names should be ignored or rejected.
Finally, compare this dynamic reader with deserializing a Dictionary<string, int>. The dictionary shape can make simple map semantics clearer, while the DOM offers more control over presence and value-kind diagnostics. Choose the smallest representation that preserves the distinctions your boundary needs, and keep the JsonDocument alive until all borrowed elements have been inspected.
A working example
using System;
using System.Linq;
using System.Collections.Generic;
using System.Globalization;
using System.Text;
using System.Text.Json;
using System.Text.Json.Serialization;
using System.Threading;
using System.Threading.Tasks;
using System.Runtime.CompilerServices;
using var document = JsonDocument.Parse("""{"a":2,"b":3}""");
int total = 0;
foreach (JsonProperty property in document.RootElement.EnumerateObject()) {
if (property.Value.ValueKind != JsonValueKind.Number) throw new FormatException("Expected number");
int value = property.Value.GetInt32();
total += value;
Console.WriteLine($"{property.Name}={value}");
}
Console.WriteLine($"total={total}");
Expected output
a=2 b=3 total=5
Dynamic shape inspection still needs explicit type and range checks.