Using it
Paste a JSON value, such as an API response, and the C# appears as you type. Attributes for picks which serializer the property names are written for: System.Text.Json, the one built into .NET, or Newtonsoft.Json (Json.NET). Write as picks ordinary classes with get and set, or positional records. Top-level name names the outermost class. The JSON stays in your browser, which matters when the sample is a real response with real data in it.
Copy the result into a .cs file and deserialize with JsonSerializer.Deserialize<Root>(json), or JsonConvert.DeserializeObject<Root>(json) for Json.NET. When the JSON is an array, the first line says which List<T> to ask for.
Why every property gets an attribute
C# properties are PascalCase and most JSON is camelCase, so the property Id has to be told that its JSON name is id. System.Text.Json does that with [JsonPropertyName("id")], from the System.Text.Json.Serialization namespace; Json.NET uses [JsonProperty("id")] from Newtonsoft.Json. Microsoft's documentation says the name set by [JsonPropertyName] applies in both directions, serializing and deserializing, and takes precedence over any naming policy.
The attribute also keeps keys that can't be C# names. A key like first-name becomes the property FirstName, 2fa becomes _2fa, and the attribute carries the real key. If two keys clean up to the same name the second gets a 2, and a property that would share its class's name gets Value on the end, because C# doesn't allow a member with the same name as its type.
No attributes leaves them off. That suits Json.NET, which matches names without regard to case by default, or System.Text.Json with PropertyNameCaseInsensitive or a camelCase naming policy set in JsonSerializerOptions.
How the types are worked out
Each object becomes a class named after the key it sits under: a lines array holds Line, and a customer object is Customer. Arrays become List<T>, and their items are merged, so a key that only some items have becomes nullable. Whole numbers are int, or long once any value passes 2,147,483,647; anything with a fraction is double; true and false are bool.
The classes are written for nullable reference types, which recent .NET project templates switch on with <Nullable>enable</Nullable>. A string that can be null or missing is string?, a number that can be is int?, and a property that's always there starts as string.Empty or new() so the compiler has nothing to warn about.
Types can only be as good as the sample. A field that is always null, or an empty array, says nothing about what it holds, so those come out as object and are worth fixing by hand. Dates stay as string, since JSON has no date type; change them to DateTime or DateTimeOffset if the format is ISO 8601.
Classes or records
A record (C# 9 and later) gets value equality, a readable ToString and with-expressions for copying, and a positional record is one line per property. Its properties are init-only, so they're set once, by the JSON. To put an attribute on a positional record's property rather than its constructor parameter, the attribute needs the property: target, as in [property: JsonPropertyName("id")], which is what this writes.
System.Text.Json deserializes records through their constructor and matches parameter names to properties without regard to case. Classes suit code that changes the object after reading it, or Entity Framework, which Microsoft notes doesn't work with records as entity types.
Questions
JsonPropertyName or JsonProperty?
[JsonPropertyName] is System.Text.Json's, in System.Text.Json.Serialization. [JsonProperty] is Newtonsoft's, in Newtonsoft.Json. Each serializer ignores the other's attribute, so use the one that matches the JsonSerializer or JsonConvert call in your code.
Why List<T> and not an array?
Both serializers read either. A List can grow after reading, which is what most code wants; change it to T[] or IReadOnlyList<T> if you prefer.
Why object for some properties?
The sample didn't show what they hold: the value was always null, the array was empty, or the items mixed types. System.Text.Json reads an object property as a JsonElement. Paste a fuller sample, or set the type by hand.
Is the JSON sent anywhere?
No. It's read and turned into C# by code running on this page.
Sources
- Microsoft Learn: How to customize property names and values with System.Text.Json
- Microsoft Learn: Use immutable types and properties (System.Text.Json, records)
- Microsoft Learn: Records (C# reference)
- Microsoft Learn: Nullable reference types
- Microsoft Learn: Migrate from Newtonsoft.Json to System.Text.Json (case-insensitive matching, JsonElement for object)
- Microsoft Learn: Compiler Error CS0542
- Json.NET documentation: JsonPropertyAttribute name
Added and reviewed . What's new






