JSON1

JSON1 / JSON to C#

JSON to C#

Generate C# classes with System.Text.Json attributes from a JSON sample. Properties are PascalCase with a JsonPropertyName holding the original key, and optional value types get a question mark.

Processed locally
InputJSON
Ready
OutputC#

Converted output appears here as you type.

Good to know

  • Every record in an array is inspected, not just the first, so a field that appears in only some of them is typed as optional rather than required.
  • Identical nested shapes are emitted once and reused, and reserved words are renamed to something legal in this language.

About this tool

C# is the one target here where the naming conventions of the language and of JSON are guaranteed to disagree: .NET properties are PascalCase, JSON keys almost never are. That makes the attribute, not the type, the interesting part of the output. This generates auto-properties with System.Text.Json attributes, nested objects as their own classes, and System.Collections.Generic imported only when a list actually appears.

The type mapping itself:

  • longJSON integers, so an id past two billion does not overflow. Narrow it to int where you know the range.
  • doubleFractional numbers. For money use decimal — double cannot represent 0.1 exactly, and .NET has a type that can.
  • long?Optional or nullable numbers and bools. A nullable value type is how C# distinguishes absent from zero; without it a missing count silently reads as 0.
  • stringReference types are left as-is. Under a project with nullable reference types enabled, expect warnings on the properties that can be absent.
  • objectA field that was null in every record. JsonElement is often the better replacement if you need to inspect it without deserialising again.
Why does every property have a JsonPropertyName?
Because the attribute makes the class work regardless of how the deserialiser is configured. A global PropertyNamingPolicy covers the common cases, but it is set once somewhere far from this class, and it cannot handle a key that is not simply a case variant. An explicit name is correct in every configuration.
Why System.Text.Json and not Newtonsoft?
It ships in the framework from .NET Core 3.0 on, so the attributes resolve with no package reference and no version conflict. Newtonsoft is still everywhere in older projects — porting is JsonPropertyName to JsonProperty plus a different using, and Newtonsoft is more forgiving about type mismatches if you need that.
Should these be records instead?
Often, yes — a record from C# 9 gives you value equality and a with expression, and a positional record deserialises through its primary constructor. The classes here are generated because they compile on every target from .NET Standard 2.0 forward, and converting one to a record is a mechanical edit; converting a record back to work on an older framework is not.
Why get and set rather than init or readonly?
init requires C# 9, and a private setter stops System.Text.Json from populating the property at all unless you add a constructor it can match. Settable properties are what deserialises everywhere with no extra ceremony — tighten them once you know your target framework.
How are optional fields decided?
Every record in an array is inspected, not just the first. A field that appears in some records and not others is typed as optional, and a value that is sometimes null widens accordingly. Generators that read only the first element get this wrong on exactly the payloads where it matters.
What happens to a key that is a reserved word?
It is renamed to something legal in the target language, and where the language supports it, an annotation records the original JSON key so serialisation still round-trips.