JSON to C# Class Converter
Generate C# classes for System.Text.Json or Newtonsoft.Json from a JSON sample, with each key in an attribute. Every value is typed, and a key that some objects lack or hold as null is nullable.
- Order.Coupon, which some objects lack, is written back as null for them. NullValueHandling = NullValueHandling.Ignore leaves out a property that is null, and so leaves out a null the JSON has too.
About JSON to C#
The objects in the JSON become C# classes that System.Text.Json or Newtonsoft.Json reads the JSON into and writes back. With either library, every property has its key in an attribute, [JsonPropertyName] or [JsonProperty], so created_at is read into CreatedAt. Even a property named as its key has one, since System.Text.Json's naming policy, such as the camelCase one ASP.NET Core sets, renames only the properties without one.
Every value at a place counts, not just the first. A number is an int, a long once one is beyond 32 bits, and a double when one is written with a fraction or an exponent, as 10.0 and 1e3 are, since both libraries refuse those for an int. Integers beyond 64 bits are a ulong or a decimal when one reads them all, and a double otherwise.
The objects at one place, such as the items of a list, make one class, with the keys in the order first seen. A key that is null in some objects, or that some objects lack, is nullable: int?, and for C# 11 and later string? too. A note names each key that some objects lack, since both libraries write it back as null for them.
For C# 11 and later, the code starts with #nullable enable, and every property that is not nullable is required: System.Text.Json then throws on an object that lacks its key, where it would otherwise read 0 or null. Newtonsoft.Json does not check required. For .NET 6 and earlier, .NET Framework or Unity, choose C# 7.3 to 10: the code then has neither, since C# 7.3 has no #nullable and required came with C# 11.
A key that holds two kinds of value, such as a string and a number, or only null, is a JsonElement for System.Text.Json and a JToken for Newtonsoft.Json, each of which holds any JSON, and objects that are always empty are a JsonObject or a JObject. A note says why, as one does for each number a double rounds or cannot hold, each string Newtonsoft.Json takes for a date and writes back in its own format, and a JSON deeper than a library reads by default.
Properties and classes are PascalCase, so user_id, userID and USER_ID all give UserId, and a name already taken gets a number, as in UserId2. The class of a list's items is singular, as Order is for orders. A property named as its class, or as a method every object has, such as ToString, has Value added, and a class named as a type the SDK's implicit usings bring in, such as File or Task, has Model added.
When the JSON is an array of objects, the root class describes them, and a note gives the type that reads the whole array. Choose Every property to make every property nullable, for an API that can leave any key out. With No attributes, a property reads only the key its name gives, and a note names each key that differs from its property's name. Everything runs in your browser.
For Kotlin, see JSON to Kotlin Data Class. For Java, try JSON to Java Class, and for TypeScript, JSON to TypeScript.
Built and maintained by Meet Shah · Last updated
What this tool is used for
- Generating System.Text.Json or Newtonsoft.Json models from an API response for an ASP.NET Core, Blazor or Unity app.
- Getting the
[JsonPropertyName]or[JsonProperty]right for keys in snake_case, or with characters a C# name cannot hold. - Starting a model for an endpoint that has no OpenAPI schema, from a response copied out of the browser or a log.
- Checking where System.Text.Json and Newtonsoft.Json read the same JSON differently, from the notes, before moving a project between them.
- Seeing how a payload's nesting maps onto nested C# classes, and which keys only some of its objects carry.
Frequently Asked Questions
- How do JSON types map to C#?
- Strings are
string, booleansbool, objects a class and arrays aList<T>. A number is anint, alongbeyond 32 bits, aulongordecimalbeyond 64, and adoublewhen a sample has a fraction or an exponent, as 10.0 and 1e3 do. A key null in some samples is nullable, as inint?. - Why does every property have an attribute?
- A property reads only the key its name gives, so
created_atis read intoCreatedAtthrough a[JsonPropertyName]or[JsonProperty]that holds the key. A property named as its key gets one too, since System.Text.Json's naming policy, such as ASP.NET Core's camelCase, renames only the properties without one. - Does System.Text.Json ignore case in property names?
- Not by default: it reads a key only into the property of exactly its name, so
nameis not read intoName. WithPropertyNameCaseInsensitive, as ASP.NET Core sets it, a class with keys that differ only by case throws anInvalidOperationException. Newtonsoft.Json tries the exact name, then ignores case. - Why are the properties required?
- For C# 11 and later, every property that is not nullable is
required, so the compiler gives no warning CS8618, and System.Text.Json throws aJsonExceptionon an object that lacks its key, where it would otherwise read 0 or null. Newtonsoft.Json does not checkrequired, and C# 7.3 to 10 has none. - Why is a property a JsonElement or a JToken?
- A key with two kinds of value, such as a string and a number, or only null, fits no one C# type, so it is a
JsonElementfor System.Text.Json or aJTokenfor Newtonsoft.Json, which hold any JSON, with a note. Without attributes it is anobject. Objects that are always empty are aJsonObjector aJObject. - Should every property be nullable?
- A sample shows only some of the keys an API can send as null or leave out: here a key that is null is nullable, and so is one that some objects lack. The API contract says which others are. Every property makes them all nullable, and none
required, so a response can leave any key out.
Common errors and gotchas
- Generating from a sample where a decimal field happens to hold a whole number, such as a price of 12: the property is an
int, and both libraries then refuse 12.5. Use a sample with a fraction, or write 12.0, which gives adouble. - Trusting the nullability one sample shows: a key present in every object of the sample can still be left out of a real response, and System.Text.Json then throws for its
requiredproperty. Choose Every property when the API contract does not say. - Leaving out the attributes and counting on System.Text.Json to ignore case: by default it reads
nameinto no property calledName, and neither library readsuser_nameintoUserNamewithout an attribute or a policy such asJsonNamingPolicy.SnakeCaseLower. - Naming a class after a type .NET already has, such as
FileorTask: the class hides that type throughout its namespace, which is why a key namedfilegives a classFileModelhere. - Letting Newtonsoft.Json read a date string into a
JTokenorobject: it parses the date and writes it back in its own format, so .1230+05:30 comes back as .123+05:30. SetDateParseHandling = DateParseHandling.Noneto keep such strings as they are. - Posting deeply nested JSON to an ASP.NET Core MVC controller: its JsonOptions set
MaxDepth = 32, so it throws on a JSON 33 levels deep that the defaults read. A note says so for a JSON that deep.